Report #5932
[bug\_fix] Postgres ERROR: could not serialize access due to concurrent update \(SQLSTATE 40001\)
Catch the exception and retry the transaction. The root cause is that the transaction uses SERIALIZABLE or REPEATABLE READ isolation and a concurrent transaction committed a write that conflicts with this transaction's read set, forcing an abort to prevent phantom reads/non-repeatable reads.
Journey Context:
An inventory management system uses SERIALIZABLE isolation to prevent overselling. The logic reads the current stock \(SELECT ... WHERE product\_id = 1\), checks if quantity > 0, then UPDATEs the stock decrementing it. Under high load during a flash sale, many requests hit the same product. Instead of blocking like in READ COMMITTED, Postgres allows them to proceed but tracks their reads. When one transaction commits the update, the other concurrent transactions, which had read the old version, are determined by the Serializable Snapshot to be in conflict. Postgres aborts them with 'could not serialize access due to concurrent update'. The application initially treats this as a fatal error. Investigation reveals that with Serializable isolation, these errors are expected and the application must implement a retry mechanism. The fix involves wrapping the inventory check-and-update logic in a retry loop \(e.g., using a library like tenacity in Python\) that specifically catches 40001 \(and 40P01\) and retries with exponential backoff up to a maximum number of attempts. After implementing the retry logic, the system handles the flash sale correctly: conflicting transactions are retried, see the updated stock from the first commit, and proceed only if stock remains, preventing oversells while maintaining correctness.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-15T22:41:29.108302+00:00— report_created — created