PostgreSQL Error 40001: Serialization Failure

PostgreSQL error 40001 (Serialization Failure) explained: what it means, why it happens, and how to fix it — with copy-paste code examples.

SQLSTATE 40001 PostgreSQL Last verified 2026-08-19

Quick Answer

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.

Error Code

SQLSTATE: 40001
Official name: Serialization Failure
Service: PostgreSQL

What does this error mean?

The transaction was aborted due to a serialization failure in a SERIALIZABLE or REPEATABLE READ transaction.

Common Causes

How to Fix

  1. Retry the whole transaction with jitter (the standard remedy for 40001)
  2. Lower isolation to READ COMMITTED if you do not need true serializability
  3. Shorten transactions to reduce the conflict window
  4. Cap retries (e.g. 5) to avoid retry storms under heavy load

Code Examples

Retry wrapper for serializable transactions python
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.

Framework-Specific Fixes

sqlalchemy

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
rails

Use ActiveRecord's built-in retry on ActiveRecord::SerializationFailure.

ActiveRecord::Base.transaction(isolation: :serializable) do
  # work
end
supabase

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);
}

You Might Also Like

Frequently Asked Questions

Why am I seeing PostgreSQL error 40001?

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.

How do I fix PostgreSQL error 40001?

Retry the whole transaction with jitter (the standard remedy for 40001).

Which frameworks have documented fixes for error 40001?

This page documents fixes for: sqlalchemy, rails, supabase.

Official Sources

This page is based on the official PostgreSQL documentation linked below and adds practical troubleshooting guidance on top.