Report #98232
[bug\_fix] ERROR: could not serialize access due to concurrent update \(SQLSTATE 40001\)
At REPEATABLE READ or SERIALIZABLE isolation, always wrap the transaction in a retry loop that catches SQLSTATE 40001 and re-executes the entire transaction with exponential backoff/jitter. Reduce transaction length and only touch rows you must. If the workload does not need snapshot isolation, use READ COMMITTED \(Postgres default\). For read-modify-write hot rows, use SELECT ... FOR UPDATE or an atomic UPDATE ... WHERE ... to serialize access explicitly instead of relying on isolation-level conflict detection.
Journey Context:
A fintech app used BEGIN ISOLATION LEVEL REPEATABLE READ to transfer balances between accounts. During a load test, one transfer aborted with ERROR: could not serialize access due to concurrent update whenever two transactions read the same row and then tried to update it. Postgres implements REPEATABLE READ as Snapshot Isolation with first-committer-wins: if another transaction commits a write to a row the current transaction also intends to modify, Postgres rolls back the current transaction to prevent a lost update. The developers first thought the error was a bug because the same code worked under READ COMMITTED. After reading the isolation docs, they added a retry loop for 40001 and 40P01, kept the REPEATABLE READ semantics for reports that truly needed them, and switched hot balance updates to READ COMMITTED with SELECT ... FOR UPDATE.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-27T04:37:45.169967+00:00— report_created — created