payloadcms / payloadcms/payload
[v3.84.1] Autosave silently does not fire on Safari (data loss — POST returns 200, DB stays empty)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 44.8k
- Forks
- 4.2k
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 53
Description
Summary
On Safari (tested 17.5 and 26.4 on macOS), the admin edit view's autosave hook
emits zero PATCH /api/<collection>/:id?autosave=true requests while the
user types in localized fields. The form does emit Server-Action POST /admin/collections/<collection>/:id requests that return 200 with a
~800-byte body, so the UI shows a "last saved Xs ago" indicator and no error.
But the underlying _<collection>_v_locales.version_title (and other
localized fields) stay empty in the database. Editors believe their work is
saved; on reload, everything is gone.
The same Payload bundle, same user, same document, in Chrome works correctly:
PATCH ?autosave=true fires every ~1s and the draft persists.
Environment
payload@3.84.1@payloadcms/next@3.84.1@payloadcms/db-postgres@3.84.1@payloadcms/richtext-lexical@3.84.1- Next.js
15.4.11, Node 22, Postgres 16 - Reproduced on:
- Safari 17.5 / macOS
- Safari 26.4 / macOS (latest)
- Working on: Chrome 147 / macOS
Collection config (relevant)
{
slug: "posts",
versions: { drafts: { autosave: { interval: 800 }, schedulePublish: true } },
access: {
read: ({ req: { user } }) => !!user || ({ status: { equals: "published" } } as never),
},
// localized fields: title, excerpt, content (lexical)
}
// localization: { locales: [fr, de], defaultLocale: "fr", fallback: true }
Reproduction
- Open the Payload admin in Safari (any version 17+), authenticated.
- Create a new post in a draft+autosave-enabled collection with localized
fields. Stay on the default locale. - Type a title. Wait the autosave debounce window (we use 800 ms).
- Watch the network tab and the database.
Expected: PATCH /api/posts/:id?autosave=true&...&locale=fr fires, DB
gets a new version row with the title.
Actual: zero PATCH requests. Only POST /admin/collections/posts/:id
requests fire (Server Action). Returns 200. DB row in _posts_v_locales
stays empty.
Evidence — same user, same document, two browsers
Server access log for the same authenticated user on the same post,
back-to-back sessions:
# Safari 26.4 (n=3 typing events)
POST /cms/admin/collections/posts/851 → 200 (body 832B)
POST /cms/admin/collections/posts/851 → 200 (body 814B)
POST /cms/admin/collections/posts/851 → 200 (body 822B)
# Zero PATCH /cms/api/posts/851?autosave=true
# Chrome 147 (same role, same doc, n=4 typing events)
POST /cms/admin/collections/posts/850 → 200
PATCH /cms/api/posts/850?autosave=true&...&locale=fr → 200 ✓ persists
POST /cms/admin/collections/posts/850 → 200
PATCH /cms/api/posts/850?autosave=true&...&locale=fr → 200 ✓ persists
DB after the Safari session:
SELECT v._locale, v.version_title FROM _posts_v_locales v
JOIN _posts_v p ON v._parent_id = p.id WHERE p.parent_id = 851 AND p.latest;
_locale | version_title
---------+---------------
fr |
de |
DB after the Chrome session (same user role, same flow):
_locale | version_title
---------+----------------------
fr | EDITOR FR TEST
de | Titre TEST admin v2
Ruled out
- Role/access: tested with
editorrole in Chrome — autosave fires
correctly and persists. Verified/api/<col>/access/:idreturns
{update: true, ...}for bothadminandeditor. - Custom auth strategy: same custom auth strategy (validating a
session cookie viapayload.auth({headers})) used in Chrome and Safari
sessions; resolves the user identically. - CORS / WAF / upstream proxy: zero
403/blocked requests in our
edge or origin gateway logs during the Safari session. - Document lock:
payload_locked_documentstable empty for the doc. - Collection access functions: defaults to
Boolean(user)for
update/create— no custom rule in play.
Hypothesis
Something in the autosave hook chain (useDebounce / useDeferredValue /
useEffectEvent / queueTask) or in requests.patch() (which is plain
fetch(url, {method: "PATCH", credentials: "include", body: formData}))
is silently no-op'ing on Safari/WebKit. The fact that the Server-Action
POST path still fires suggests the form itself is functional — only the
client-side autosave PATCH submit is dropped.
We have not yet identified whether the fetch call throws, the hook
never runs, or requests.patch resolves without a network round-trip.
Happy to attach Safari Web Inspector traces if useful — let me know what
would help triage.
Workaround
Hard banner at the top of every editable doc, detecting WebKit-non-Chromium
UA, telling editors to use Chrome/Firefox until a fix lands. Better than
silent data loss but obviously not a fix.
Impact
Two editors lost their work before we identified the cause; our prior
"fixes" (validated only in Chrome) gave false confidence. This is
effectively silent data corruption for any editor on Safari — a common
browser on macOS.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.