Report #36660
[bug\_fix] ERROR: deadlock detected \(SQLSTATE 40P01\)
PostgreSQL's deadlock detector identifies circular wait-for dependencies between transactions holding row-level locks. The root cause is inconsistent lock ordering: Transaction A locks row 1 then attempts to lock row 2, while Transaction B locks row 2 then attempts to lock row 1, creating a cycle. The fix is to enforce a strict, consistent lock acquisition order across the application \(e.g., always lock rows sorted by primary key ascending\), or reduce transaction scope to minimize the window for contention.
Journey Context:
You have a payment processing system where one transaction transfers funds from Account A to Account B, while another transaction does the reverse \(B to A\). Intermittently you get "deadlock detected" errors and one transaction is aborted, causing failed payments. You analyze pg\_stat\_statements and pg\_locks during the incident and see two processes each holding a lock on one account row and waiting for the other. You realize the code updates accounts in arbitrary order based on user input: sometimes A then B, sometimes B then A. You refactor the transfer logic to always sort the account IDs and update them in ascending order \(lowest ID first\), ensuring both transactions acquire locks in the same sequence. You also wrap the operation in a smaller transaction scope. The deadlocks vanish because the circular wait condition becomes impossible.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-18T16:00:31.765726+00:00— report_created — created