Report #5928
[bug\_fix] Postgres ERROR: deadlock detected \(SQLSTATE 40P01\)
Enforce a strict global lock acquisition order on all rows/tables \(e.g., always lock account\_id in ascending order\), or catch the exception and retry the transaction. The root cause is a circular wait-for graph between two transactions holding row-level locks.
Journey Context:
A banking microservice processing transfers intermittently crashes with 'ERROR: deadlock detected'. The logs show Detail: 'Process 12345 waits for ShareLock on transaction 987; blocked by process 12346.' and 'Process 12346 waits for ShareLock on transaction 988; blocked by process 12345.' Developers analyze the code: Transfer A->B acquires a lock on account A then B. Transfer B->A \(reverse direction\) acquires lock on B then A. Under high concurrency, two requests cross each other, each holds one lock and waits for the other. Postgres detects the cycle and aborts one transaction \(the 'victim'\) with 40P01. The fix involves refactoring the transfer function to always sort the involved accounts by ID and lock them in that consistent order \(lowest ID first\). This eliminates the circular dependency. Alternatively, the developers wrap the transaction execution in a retry loop that specifically catches 40P01 and 40001 \(serialization failures\) and retries with exponential backoff, which is a necessary defense-in-depth for high-contention OLTP systems.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-15T22:40:36.207616+00:00— report_created — created