Jump to solution
Verify

The Fix

Fixes a bug where an exception caused by a disconnection clobbers a server error already received as a result, specifically for idle-in-transaction timeout.

Based on closed psycopg/psycopg issue #988 · PR/commit linked

Production note: Watch p95/p99 latency and retry volume; timeouts can turn into retry storms and duplicate side-effects.

Jump to Verify Open PR/Commit
@@ -23,6 +23,10 @@ Psycopg 3.2.4 (unreleased) - Make sure that the notifies callback is called during the use of the `~Connection.notifies()` generator (:ticket:`#972`). +- Raise the correct error returned by the database (such as `!AdminShutdown` + or `!IdleInTransactionSessionTimeout`) instead of a generic + `OperationalError` when a server error causes a client disconnection
repro.py
import psycopg from time import sleep with psycopg.connect("...") as conn: with conn.cursor() as cursor: cursor.execute("SET SESSION idle_in_transaction_session_timeout = 1000") sleep(2) cursor.execute("SELECT * from pg_tables") # Exception raised: # OperationalError: consuming input failed: server closed the connection unexpectedly # This probably means the server terminated abnormally # before or while processing the request.
verify
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
fix.md
Option A — Apply the official fix\nFixes a bug where an exception caused by a disconnection clobbers a server error already received as a result, specifically for idle-in-transaction timeout.\nWhen NOT to use: This fix should not be applied if the application relies on the generic error handling behavior.\n\n

Why This Fix Works in Production

  • Trigger: psycopg.DatabaseError: server closed the connection unexpectedly
  • Mechanism: The psycopg3 library raises a generic OperationalError instead of the specific IdleInTransactionSessionTimeout error
Production impact:
  • If left unfixed, tail latency can spike under load and surface as timeouts/retries (amplifying incident impact).

Why This Breaks in Prod

  • The psycopg3 library raises a generic OperationalError instead of the specific IdleInTransactionSessionTimeout error
  • Surfaces as: psycopg.DatabaseError: server closed the connection unexpectedly

Proof / Evidence

Discussion

High-signal excerpts from the issue thread (symptoms, repros, edge-cases).

“This patch: seems to solve the problem. Will test it more thoroughly and prepare a MR.”
@dvarrazzo · 2025-01-07 · source
“I'm not sure to follow everything 😅, but a big thank you for how quick your are handling this!”
@b0uh · 2025-01-09 · source
“It seems a bug indeed”
@dvarrazzo · 2025-01-07 · repro detail · source
“I think I'm making sense of the problem in psycopg 3”
@dvarrazzo · 2025-01-07 · source

Failure Signature (Search String)

  • psycopg.DatabaseError: server closed the connection unexpectedly

Error Message

Stack trace
error.txt
Error Message ------------- psycopg.DatabaseError: server closed the connection unexpectedly This probably means the server terminated abnormally before or while processing the request. invalid socket
Stack trace
error.txt
Error Message ------------- [179755] pq_execute: executing SYNC query: pgconn = 0x60df25d95af0 [179755] SELECT * from pg_tables 2025-01-07 23:45:42.250610 F 28 Query "SELECT * from pg_tables" 2025-01-07 23:45:42.250762 B 122 ErrorResponse S "FATAL" V "FATAL" C "25P03" M "terminating connection due to idle-in-transaction timeout" F "postgres.c" L "3398" R "ProcessInterrupts" \x00 [179755] pq_execute: entering synchronous DBAPI compatibility mode [179755] pq_fetch: pgstatus = PGRES_FATAL_ERROR [179755] pq_fetch: uh-oh, something FAILED: status = 7 pgconn = 0x76147212ad40 [179755] pq_raise: PQresultErrorMessage: err=server closed the connection unexpectedly This probably means the server terminated abnormally before or while processing the request. [179755] pq_raise: err2=server closed the connection unexpectedly This probably means the server terminated abnormally before or while processing the request. [179755] curs_execute: res = -1, pgres = (nil) [179755] curs_close: cursor at 0x7614721056c0 closed Traceback (most recent call last): File "/home/piro/dev/psycopg2/test_close_conn.py", line 32, in <module> cursor.execute("SELECT * from pg_tables") psycopg2.OperationalError: server closed the connection unexpectedly This probably means the server terminated abnormally before or while processing the request. [179755] conn_close: PQfinish called
Stack trace
error.txt
Error Message ------------- PGconn.send_query(b'SELECT * from pg_tables') F 28 Query "SELECT * from pg_tables" <- None PGconn.flush() <- 0 PGconn.is_busy() <- 1 PGconn.consume_input() <- None PGconn.is_busy() B NN ErrorResponse S "FATAL" V "FATAL" C "25P03" M "terminating connection due to idle-in-transaction timeout" F "SSSS" L "SSSS" R "SSSS" \x00 <- 0 PGconn.notifies() <- None PGconn.get_result() <- <psycopg.pq.pq_ctypes.PGresult [FATAL_ERROR] at 0x7c902e39e800> PGconn.is_busy() <- 1 PGconn.consume_input() PGconn.status -> 1 Traceback (most recent call last): File "/home/piro/dev/psycopg3/test_close_conn.py", line 33, in <module> ... psycopg.OperationalError: consuming input failed: terminating connection due to idle-in-transaction timeout server closed the connection unexpectedly This probably means the server terminated abnormally before or while processing the request.

Minimal Reproduction

repro.py
import psycopg from time import sleep with psycopg.connect("...") as conn: with conn.cursor() as cursor: cursor.execute("SET SESSION idle_in_transaction_session_timeout = 1000") sleep(2) cursor.execute("SELECT * from pg_tables") # Exception raised: # OperationalError: consuming input failed: server closed the connection unexpectedly # This probably means the server terminated abnormally # before or while processing the request.

What Broke

Users experience unclear disconnection errors when idle_in_transaction_session_timeout is triggered.

Why It Broke

The psycopg3 library raises a generic OperationalError instead of the specific IdleInTransactionSessionTimeout error

Fix Options (Details)

Option A — Apply the official fix

Fixes a bug where an exception caused by a disconnection clobbers a server error already received as a result, specifically for idle-in-transaction timeout.

When NOT to use: This fix should not be applied if the application relies on the generic error handling behavior.

Fix reference: https://github.com/psycopg/psycopg/pull/989

Last verified: 2026-02-09. Validate in your environment.

Get updates

We publish verified fixes weekly. No spam.

Subscribe

When NOT to Use This Fix

  • This fix should not be applied if the application relies on the generic error handling behavior.

Verify Fix

verify
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.

Did This Fix Work in Your Case?

Quick signal helps us prioritize which fixes to verify and improve.

Prevention

  • Make timeouts explicit and test them (unit + integration) to avoid silent behavior changes.
  • Instrument retries (attempt count + reason) and alert on spikes to catch dependency slowdowns.

Related Issues

No related fixes found.

Sources

We don’t republish the full GitHub discussion text. Use the links above for context.