Report #46207
[bug\_fix] could not serialize access due to concurrent update \(PostgreSQL SERIALIZABLE isolation failure\)
Implement application-level retry logic that catches the 40001 SQLSTATE error \(serialization\_failure\), rolls back the transaction, and retries with exponential backoff and jitter. Alternatively, reduce the isolation level to READ COMMITTED if the business logic does not require true serializability, or use advisory locks to manually serialize conflicting operations. Root cause: Under SERIALIZABLE or REPEATABLE READ isolation, PostgreSQL uses Serializable Snapshot Isolation \(SSI\) which detects rw-conflicts between concurrent transactions at commit time and aborts one transaction to prevent write skew and anomalies.
Journey Context:
A fintech developer implements a funds transfer feature that debits one account and credits another. To prevent race conditions and ensure strict consistency, the developer explicitly sets the transaction isolation level to SERIALIZABLE, believing this is the safest option. During load testing with 100 concurrent transfers, the application logs fill with 'ERROR: could not serialize access due to concurrent update' \(SQLSTATE 40001\). The developer initially interprets this as a bug in PostgreSQL or the driver, but after researching the PostgreSQL documentation on Serializable Snapshot Isolation \(SSI\), they understand that these errors are actually the database correctly preventing write skew by aborting transactions that have rw-dependencies. The developer implements a retry wrapper in Python using tenacity that specifically catches psycopg2.errors.SerializationFailure, waits a random 10-50ms \(to avoid thundering herd\), and retries up to 5 times. They also optimize the transaction to hold locks for the shortest possible time by moving validation logic outside the transaction block. After these changes, the load test passes with 100% success, handling thousands of concurrent transfers with only a small percentage of transactions requiring a retry.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-19T08:01:56.278865+00:00— report_created — created