40001 — could not serialize access
PostgreSQL 40001 can reject a REPEATABLE READ target changed since its snapshot or a SERIALIZABLE dependency conflict; roll back and retry the complete transaction with fresh decisions, or return controlled failure.
Reproduce it
Two sessions. The -- [A] and -- [B] markers say who runs each statement, top to bottom.
-- [A] open a snapshot and read the row
BEGIN ISOLATION LEVEL REPEATABLE READ;
SELECT balance FROM accounts WHERE id = 1; -- sees 100
-- [B] change that same row and commit
UPDATE accounts SET balance = 150 WHERE id = 1;
-- [A] now try to write the row you read
UPDATE accounts SET balance = 200 WHERE id = 1;A's target was changed after its snapshot, so its UPDATE fails with 40001. A cannot continue ordinary queries in the failed block. The complete Scenario includes immediate and waiting conflict branches; the lost-update example separately executes a successful fresh retry. Retry the full set of reads and decisions, with a bound or controlled failure. A stale human edit can require reconsideration, and database rollback does not undo external effects. Retrying is not guaranteed to succeed.
Run it yourself
This is the lead example on the Repeatable Read lesson, rendered there as a verified transcript against a real database. The retry loop that turns this failure into a safe write lives in Retrying serialization failures, and Serializable is the stricter level that raises the same 40001 for a wider set of conflicts.
The MySQL side
InnoDB uses locking SERIALIZABLE reads inside explicit transactions. Conflicts can wait and then succeed or fail; this PostgreSQL schedule does not predict every MySQL outcome. MySQL deadlock errno 1213 has SQLSTATE 40001; row-lock timeout 1205 has different rollback scope. Check the engine and driver representation before selecting recovery.