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.
@@ -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
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.
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
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
- 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
- GitHub issue: #988
- Fix PR: https://github.com/psycopg/psycopg/pull/989
- Reproduced locally: No (not executed)
- Last verified: 2026-02-09
- Confidence: 0.70
- Did this fix it?: Yes (upstream fix exists)
- Own content ratio: 0.29
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.”
“I'm not sure to follow everything 😅, but a big thank you for how quick your are handling this!”
“It seems a bug indeed”
“I think I'm making sense of the problem in psycopg 3”
Failure Signature (Search String)
- psycopg.DatabaseError: server closed the connection unexpectedly
Error Message
Stack trace
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 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 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
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.
Fix reference: https://github.com/psycopg/psycopg/pull/989
Last verified: 2026-02-09. Validate in your environment.
When NOT to Use This Fix
- This fix should not be applied if the application relies on the generic error handling behavior.
Verify Fix
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.