PostgreSQL error 40001 (Serialization Failure) explained: what it means, why it happens, and how to fix it — with copy-paste code examples.
Retry the whole transaction with jitter (the standard remedy for 40001). If that does not apply, lower isolation to READ COMMITTED if you do not need true serializability — the full checklist is below.
SQLSTATE: 40001
Official name: Serialization Failure
Service: PostgreSQL
The transaction was aborted due to a serialization failure in a SERIALIZABLE or REPEATABLE READ transaction.
def run_serializable(fn, max_retries=5):
for attempt in range(max_retries):
try:
with conn.transaction(isolation='SERIALIZABLE'):
return fn()
except psycopg.errors.SerializationFailure:
continue
raise RuntimeError('max retries exceeded')
Serialization failures are expected under SERIALIZABLE isolation; the protocol is to retry the entire transaction.
Retry the transaction when the underlying error SQLSTATE is 40001.
for _ in range(5):
try:
run_transaction(session)
break
except OperationalError as e:
if getattr(e.orig, 'sqlstate', None) == '40001':
session.rollback(); continue
raise
Use ActiveRecord's built-in retry on ActiveRecord::SerializationFailure.
ActiveRecord::Base.transaction(isolation: :serializable) do
# work
end
The PostgREST API surfaces serialization failures as HTTP 409; retry the request with backoff.
for (let i = 0; i < 5; i++) {
const { error } = await supabase.from('t').insert(row);
if (!error) break;
await sleep(2 ** i * 50);
}
Most often this happens when two SERIALIZABLE transactions read and write overlapping data and cannot both commit, or when using SERIALIZABLE isolation on write-heavy hot paths.
Retry the whole transaction with jitter (the standard remedy for 40001).
This page documents fixes for: sqlalchemy, rails, supabase.
Recommendations are editorial — DB Error Reference takes no payment or affiliate fees for tool listings.
This page is based on the official PostgreSQL documentation linked below and adds practical troubleshooting guidance on top.