examples · errors · 13 / 19
13. 409 - optimistic-concurrency conflict
← Errors exampleswhat this error means
Important context first: by default, OriginChain row writes are last-writer-wins - two concurrent PUTs on the same key both succeed, and the later one overwrites the earlier one. No 409.
OCC (optimistic concurrency control) is opt-in. You enable it by passing the row's current version in an If-Match: <oc_row_version> header. If the row's actual version differs at commit time, the write is rejected with this 409 and the body tells you the current version so you can re-fetch, re-apply, and retry.
what triggers it
A conditional PUT where the If-Match version no longer matches.
PUT /v1/tenants/:t/rows/:table/:pk with If-Match
curl -X PUT "https://$OC_HOST/v1/tenants/$OC_TENANT/rows/shop.customers/c_42" \
-H "Authorization: Bearer $OC_TOKEN" \
-H "If-Match: 17" \
-H "Content-Type: application/json" \
-d '{"id": "c_42", "email": "alice@example.com", "tier": "platinum"}' the canonical response body
{
"error": "write_conflict",
"message": "row 'c_42' is at version 18, expected 17",
"retry": true,
"current_version": 18
} how to recover
- Re-read the row to get the current state and version.
- Re-apply your business logic on top of the new state (merge, re-validate, etc).
- Retry the PUT with
If-Match: <new_version>. - The SDKs offer a
update_with_retry()helper that wraps the read-merge-retry loop. retry: true- but only after re-fetching. Blind retry of the same bytes will fail the same way.
common upstream causes
- Two workers picking up the same job from a queue and racing on the same row.
- Background reconciler and user-facing edit landing in the same millisecond.
- Re-using a stale version number from an in-memory cache.
- Mobile client with an offline edit syncing after the server already advanced.
- Wrong row's version copied into
If-Matchfrom another response.