Describe the Bug
In payload@3.90.2, checkDocumentLockStatus (packages/payload/src/utilities/checkDocumentLockStatus.ts) looks up payload-locked-documents through payload.db.find(...) without passing req. The deleteMany call a few lines below does pass req.
With @payloadcms/db-postgres, update and delete operations with overrideLock: false (the default for REST PATCH/DELETE) run inside a transaction. Each one holds its transaction connection and then asks the pool for a second connection for this lock-status read. When about pool.max updates or deletes run at the same time, every connection is idle in transaction waiting for the pool. The server hangs indefinitely, and so does every other request, including POST /api/users/login.
pg_stat_activity shows pool.max connections idle in transaction (wait_event Client), and the last statement is the operation's own select of the document.
Link to the code that causes the issue
https://github.com/payloadcms/payload/blob/main/packages/payload/src/utilities/checkDocumentLockStatus.ts
Reproduction Steps
- Postgres adapter with a small pool:
pool: { max: 10 }.
- Create 11+ posts.
- Send
PATCH /api/posts/:id for all of them in parallel (for example with Promise.all), or call Local API payload.update({ collection, id, data, overrideLock: false }) 11+ times at once.
- None of the requests finishes, and the server stops answering.
Passing req to that find fixes it. It is the same change as the one already applied to deleteMany below it:
const result = await payload.db.find({
collection: lockedDocumentsCollectionSlug,
limit: 1,
pagination: false,
+ req: payload.db.name === 'mongoose' ? undefined : req,
sort: '-updatedAt',
where: lockedDocumentQuery,
})
We run this as a local pnpm patch. A regression test with pool + 2 parallel updates and deletes passes with the patch, and the 423 for a document locked by another user still works inside the transaction.
Which area(s) are affected?
db-postgres, area: core
Environment Info
payload: 3.90.2
@payloadcms/db-postgres: 3.90.2
next: 16.x
Node: 24
Describe the Bug
In
payload@3.90.2,checkDocumentLockStatus(packages/payload/src/utilities/checkDocumentLockStatus.ts) looks uppayload-locked-documentsthroughpayload.db.find(...)without passingreq. ThedeleteManycall a few lines below does passreq.With
@payloadcms/db-postgres, update and delete operations withoverrideLock: false(the default for RESTPATCH/DELETE) run inside a transaction. Each one holds its transaction connection and then asks the pool for a second connection for this lock-status read. When aboutpool.maxupdates or deletes run at the same time, every connection isidle in transactionwaiting for the pool. The server hangs indefinitely, and so does every other request, includingPOST /api/users/login.pg_stat_activityshowspool.maxconnectionsidle in transaction(wait_eventClient), and the last statement is the operation's ownselectof the document.Link to the code that causes the issue
https://github.com/payloadcms/payload/blob/main/packages/payload/src/utilities/checkDocumentLockStatus.ts
Reproduction Steps
pool: { max: 10 }.PATCH /api/posts/:idfor all of them in parallel (for example withPromise.all), or call Local APIpayload.update({ collection, id, data, overrideLock: false })11+ times at once.Passing
reqto thatfindfixes it. It is the same change as the one already applied todeleteManybelow it:const result = await payload.db.find({ collection: lockedDocumentsCollectionSlug, limit: 1, pagination: false, + req: payload.db.name === 'mongoose' ? undefined : req, sort: '-updatedAt', where: lockedDocumentQuery, })We run this as a local
pnpm patch. A regression test with pool + 2 parallel updates and deletes passes with the patch, and the 423 for a document locked by another user still works inside the transaction.Which area(s) are affected?
db-postgres, area: core
Environment Info