Skip to content

Manual and reschedule allocations throw 'Failed to deserialize column of type void': the pg_advisory_xact_lock guard uses $queryRaw under the Prisma 7 driver adapter #1518

Description

@teetangh

What happens

SlotAllocationService.guardInitialAllocationInTx (utils/slotAllocation/SlotAllocationService.ts ~L759-765, added by #998) takes the per-event advisory lock with

await tx.$queryRaw`SELECT pg_advisory_xact_lock(hashtextextended(${key}, 42))`;

pg_advisory_xact_lock returns void. Under Prisma 7's driver adapter the result row carries a column of Postgres type void, which the adapter cannot deserialise, so the call throws PrismaClientKnownRequestError: Failed to deserialize column of type 'void' before the allocation begins. Every path that reaches the guard fails: manualAllocate from the request calendar (~L1567) and the reschedule allocation (POST /api/appointments/[appointmentId]/reschedule).

Evidence

Sentry FAMILIARISE_WEB-2W, 2 events on 2026-09-06 (~02:00Z) from the dev branch deploy, trace through manualAllocate → guardInitialAllocationInTx. The same code is on prod (git show origin/prod:utils/slotAllocation/SlotAllocationService.ts carries the call), so production manual allocation and reschedule are affected too. Wave 1–3 E2E did not exercise these paths (checkout with direct slots does not take this guard), which is why it went unnoticed.

Fix

Take the lock through a statement whose result Prisma does not deserialise, or give it a deserialisable shape: await tx.$executeRaw\SELECT pg_advisory_xact_lock(hashtextextended(${key}, 42))`(the common Prisma idiom for advisory locks), orSELECT pg_advisory_xact_lock(...) IS NULL(boolean). Keep the lock inside the transaction and the key unchanged. Grep the repo for any other$queryRawthat selects avoid-returning function (pg_advisory_lock, pg_notify, set_config` with void results) and fix them the same way. One pin: the guard issues the lock through the chosen call and allocation proceeds; a test that runs the raw statement against the test database if one exists, else a source-level pin plus a Prisma-mock expectation.

Found by the Sentry poller on 2026-09-06.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bookingBooking, scheduling, slots, reschedule, cancellationbugSomething isn't workinglaunch: pre-mvpGates launch — money, data, or a failure we would not detectpriority: critical

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions