Skip to content

fix: handle concurrent autosave write conflicts gracefully#16216

Merged
JarrodMFlesch merged 4 commits into
payloadcms:mainfrom
robertjbass:fix/save-version-undefined-guard
Apr 13, 2026
Merged

fix: handle concurrent autosave write conflicts gracefully#16216
JarrodMFlesch merged 4 commits into
payloadcms:mainfrom
robertjbass:fix/save-version-undefined-guard

Conversation

@robertjbass

@robertjbass robertjbass commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

What?

Two-part fix for intermittent 500s during autosave on serverless environments.

  1. updateLatestVersion catches errors from updateVersion/updateGlobalVersion and checks whether a concurrent write already succeeded before falling back to createVersion
  2. saveVersion re-throws instead of return undefined! so genuine failures still surface as real errors

Why?

On serverless, concurrent autosave requests race to update the same version row. The losing request gets a DB error. Previously saveVersion caught it and returned undefined!, which was assigned to result. Downstream field hooks then accessed properties on undefined:

TypeError: Cannot read properties of undefined (reading '_status')

How?

When updateVersion fails, we re-query the row and check if updatedAt has moved — if it has, a concurrent request already committed and we return that result. If not, we fall back to createVersion. If that also fails, saveVersion re-throws.

Fixes #16217


…t TypeError and data desync

saveVersion() catches errors during version creation and returns
undefined, which causes two problems:

1. The callers pass undefined as doc to afterRead/afterChange field
   hooks, which then throw:
     TypeError: Cannot read properties of undefined (reading '_status')
     TypeError: Cannot read properties of undefined (reading 'lastPublishedAt')

2. The main document table can update successfully while the version
   save silently fails, leaving the document and version history out
   of sync.

By re-throwing instead of returning undefined, the entire transaction
is rolled back cleanly when version creation fails. The error is
already logged before the throw, so no diagnostic information is lost.

This is intermittent and primarily surfaces on serverless deployments
(Vercel) where concurrent autosave PATCH requests race within the
same function invocation.
@robertjbass robertjbass force-pushed the fix/save-version-undefined-guard branch from 9986861 to 3800a3f Compare April 8, 2026 20:37
@PatrikKozak PatrikKozak changed the title fix: guard against saveVersion returning undefined to prevent TypeError in update operations fix: handle concurrent autosave write conflicts gracefully Apr 8, 2026
Comment thread packages/payload/src/versions/updateLatestVersion.ts

@JarrodMFlesch JarrodMFlesch left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should rework the nested try catch. I have addressed this!

@JarrodMFlesch JarrodMFlesch dismissed their stale review April 10, 2026 20:09

Changes made

@JarrodMFlesch JarrodMFlesch enabled auto-merge (squash) April 10, 2026 20:10
@PatrikKozak PatrikKozak self-assigned this Apr 13, 2026
@JarrodMFlesch JarrodMFlesch merged commit e8502fa into payloadcms:main Apr 13, 2026
324 of 326 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

🚀 This is included in version v3.83.0

milamer pushed a commit to milamer/payload that referenced this pull request Apr 20, 2026
…s#16216)

### What?

Two-part fix for intermittent 500s during autosave on serverless
environments.

1. `updateLatestVersion` catches errors from
`updateVersion`/`updateGlobalVersion` and checks whether a concurrent
write already succeeded before falling back to `createVersion`
2. `saveVersion` re-throws instead of `return undefined!` so genuine
failures still surface as real errors

### Why?

On serverless, concurrent autosave requests race to update the same
version row. The losing request gets a DB error. Previously
`saveVersion` caught it and returned `undefined!`, which was assigned to
`result`. Downstream field hooks then accessed properties on
`undefined`:

```
TypeError: Cannot read properties of undefined (reading '_status')
```

### How?

When `updateVersion` fails, we re-query the row and check if `updatedAt`
has moved — if it has, a concurrent request already committed and we
return that result. If not, we fall back to `createVersion`. If that
also fails, `saveVersion` re-throws.

Fixes payloadcms#16217

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1213985147428664

---------

Co-authored-by: Patrik Kozak <35232443+PatrikKozak@users.noreply.github.com>
Co-authored-by: Jarrod Flesch <jarrodmflesch@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: intermittent TypeError on autosave when saveVersion fails on serverless (Vercel)

3 participants