Skip to content

Schema Mismatch

  • Push / pull requests return HTTP 409 with body { "error": "schema mismatch", "expected": "..." }
  • client.onError fires with { kind: "schema-mismatch", phase, expected }
  • The Devtools panel shows a “schema mismatch” badge

The SyncHandlerOptions.schemaVersion on the Worker doesn’t equal the PlasmaClientOptions.schemaVersion on the browser client. The server refuses to accept mutations under an unknown schema version.

  1. You bumped SCHEMA_VERSION in the shared file but didn’t deploy the server. The client build has v2; the deployed Worker still runs v1.
  2. You deployed the server first. The Worker has v2; the users’ cached client build still has v1.
  3. You have two schema.ts files that drifted. The Worker’s copy and the client’s copy accidentally have different string constants.

Deploy the Worker to catch up:

Terminal window
pnpm wrangler deploy

Then check the log stream that the new version is receiving the push:

Terminal window
pnpm wrangler tail

If your users have a stale bundle cached, you need them to reload. The cleanest UX:

createPlasmaClient({
...,
onSchemaMismatch: async ({ phase }) => {
if (confirm("This app has been updated. Reload to continue?")) {
window.location.reload()
return "stay"
}
return "stay"
},
})

Returning "stay" leaves the local IDB alone; the user is stuck until they reload. Alternatively return "reset" to wipe the local IDB (see the trade-off below).

Return Effect
"stay" Local IDB untouched. Sync loop keeps failing until the mismatch is resolved. User can keep making local mutations (they land in outbox).
"reset" Local IDB wiped: base stores, user stores, outbox, cookie, clientID all rotated. Next pull hydrates from scratch.
  • Bump SCHEMA_VERSION deliberately. See Migrations for what changes require a bump vs what changes don’t.
  • Deploy server before client. The server accepts older client schema versions silently (as long as no additive-required column is missing); a new client hitting an old server is the failure mode.
  • Version your bundles. Cache-Control on the JS bundle should encourage prompt reloading on version bumps.

Force a mismatch locally to test your onSchemaMismatch UX:

dev.ts
const plasma = createPlasmaClient({
...,
schemaVersion: "wrong-version", // ≠ what the Worker returns
})