Description
Autosave PATCH requests intermittently return 500 with a generic {"errors":[{"message":"Something went wrong."}]} response body. The actual error in server logs is TypeError: Cannot read properties of undefined (reading '_status') (or 'lastPublishedAt'), originating in Payload's internal field hook processing.
The 500 response gives no indication of the root cause, making this very difficult to debug. We spent significant time investigating connection pooling, database limits, and middleware before finding the actual source in Vercel function logs.
Reproduction
Config:
const Posts: CollectionConfig = {
slug: 'posts',
versions: {
drafts: {
autosave: true,
},
},
fields: [
{ name: 'title', type: 'text' },
{ name: 'content', type: 'richText' },
],
}
Steps:
- Create and publish a document in the admin panel
- Open the published document for editing
- Edit content so autosave fires PATCH requests
- When two autosave PATCHes overlap within the same serverless function invocation, one intermittently returns 500
Environment:
- Payload 3.81.0 and 3.82.0 (both affected)
@payloadcms/db-postgres with Neon (PostgreSQL)
- Deployed on Vercel (serverless functions)
- Cannot reproduce on local dev server (single-process, requests are serialized)
Error
The client receives:
{"errors":[{"message":"Something went wrong."}]}
Vercel function logs show the real error:
TypeError: Cannot read properties of undefined (reading '_status')
at re (node_modules__pnpm_0snv283._.js:155:134460)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async rC (node_modules__pnpm_0snv283._.js:155:142262)
at async en (node_modules__pnpm_0snv283._.js:155:99079)
Sometimes manifests as:
TypeError: Cannot read properties of undefined (reading 'lastPublishedAt')
Which property triggers the error depends on which field is processed first.
Root Cause
Traced through the Payload source:
saveVersion() catches errors and returns undefined! (saveVersion.ts#L137)
- The callers in update operations assign this directly to
result without a null check (update.ts#L379)
result (now undefined) is passed as doc to afterRead and afterChange field hooks
- Field hooks access
doc.id, doc._status, etc. on the undefined value
The transient saveVersion failure is triggered by concurrent autosave requests racing in updateLatestVersion. This is common on Vercel when:
- Live preview is enabled (the preview iframe polls while autosave fires)
- afterChange hooks defer work into
after() from next/server, keeping the function invocation alive longer and increasing the window for overlapping requests
Vercel logs on failing requests consistently show Peak Concurrency of 2-3 requests on the same function invocation.
Observations
- Database is healthy (Neon pooler shows plenty of capacity, 0ms wait time, only ~8 actual DB connections)
- Not related to connection pooling or database limits
- The failing and succeeding request can be identical, differing only by which Vercel function instance handles them
- Clicking publish repeatedly eventually succeeds when a request happens to land on an invocation without concurrency pressure
Proposed Fix
PR: #16216
Throw error instead of returning undefined:
packages/payload/src/versions/saveVersion.ts#137
- return undefined!
+ throw err
Description
Autosave PATCH requests intermittently return 500 with a generic
{"errors":[{"message":"Something went wrong."}]}response body. The actual error in server logs isTypeError: Cannot read properties of undefined (reading '_status')(or'lastPublishedAt'), originating in Payload's internal field hook processing.The 500 response gives no indication of the root cause, making this very difficult to debug. We spent significant time investigating connection pooling, database limits, and middleware before finding the actual source in Vercel function logs.
Reproduction
Config:
Steps:
Environment:
@payloadcms/db-postgreswith Neon (PostgreSQL)Error
The client receives:
{"errors":[{"message":"Something went wrong."}]}Vercel function logs show the real error:
Sometimes manifests as:
Which property triggers the error depends on which field is processed first.
Root Cause
Traced through the Payload source:
saveVersion()catches errors and returnsundefined!(saveVersion.ts#L137)resultwithout a null check (update.ts#L379)result(nowundefined) is passed asdoctoafterReadandafterChangefield hooksdoc.id,doc._status, etc. on the undefined valueThe transient
saveVersionfailure is triggered by concurrent autosave requests racing inupdateLatestVersion. This is common on Vercel when:after()fromnext/server, keeping the function invocation alive longer and increasing the window for overlapping requestsVercel logs on failing requests consistently show Peak Concurrency of 2-3 requests on the same function invocation.
Observations
Proposed Fix
PR: #16216
Throw error instead of returning undefined:
packages/payload/src/versions/saveVersion.ts#137