cockroachdb / cockroachdb/cockroach
sql: idle_in_transaction_session_timeout surfaces an internal "read tcp: i/o timeout" error (SQLSTATE XXUUU) instead of a purposeful timeout error like PostgreSQL's 25P03
- Dominant language
- Go
- Stars
- 32.5k
- Forks
- 4.1k
- PR merge metrics
- PR metrics pending
Description
## Describe the problem
When `idle_in_transaction_session_timeout` fires, PostgreSQL terminates the session with a
deliberate, identifiable error:
```
FATAL: 25P03: terminating connection due to idle-in-transaction timeout
```
CockroachDB instead leaks the pgwire connection read-deadline error to the client as an
ErrorResponse with SQLSTATE `XXUUU` (uncategorized internal error) and a net-layer message,
then closes the connection:
```
ERROR: read tcp 172.17.0.2:26257->192.168.65.1:29501: i/o timeout
SQLSTATE: XXUUU
```
Nothing in the code or the message indicates that a configured session timeout fired. The
consequences:
1. **Undiagnosable from the client side.** Applications and on-call engineers see what looks
like a network failure, not an intentional server action. There is no way to
programmatically distinguish "the server enforced idle_in_transaction_session_timeout"
from a genuine broken connection.
2. **PostgreSQL incompatibility.** Drivers, ORMs, and frameworks that special-case 25P03
(or at least a purposeful FATAL) get an uncategorized internal error instead.
3. **XXUUU is documented as an internal error class**, which normally signals a CockroachDB
bug and is the kind of thing error-reporting pipelines (e.g. Sentry) are configured to
page on — but here it is routine, expected behavior.
4. **Framework interaction makes it worse.** With Spring JDBC (spring-jdbc 6.2.18, pgjdbc
42.7.8/42.7.10, HikariCP), the XXUUU error surfaces as `UncategorizedSQLException`, and
the subsequent rollback attempt on the dead connection fails and *overrides* the original
exception, so the application ultimately catches a generic `TransactionSystemException`
("JDBC rollback failed") with no SQLSTATE at all.
By contrast, `statement_timeout` and `transaction_timeout` both return a clean, purposeful
`57014` with a message naming the timeout — the idle timeout is the odd one out.
## To Reproduce
Single-node insecure cluster, any client that reads the final ErrorResponse (psycopg shown;
the `cockroach sql` CLI just reports "connection lost" because it treats the EOF first):
```python
import time, psycopg
conn = psycopg.connect("postgresql://root@localhost:26257/defaultdb?sslmode=disable", autocommit=True)
conn.execute("SET idle_in_transaction_session_timeout='1s'")
with conn.transaction():
conn.execute("SELECT 1")
time.sleep(2.5)
conn.execute("SELECT 2")
```
Result (reproduces 3/3 runs):
```
psycopg.errors.InternalError_: read tcp 172.17.0.2:26257->192.168.65.1:29501: i/o timeout
SQLSTATE: XXUUU
```
## Expected behavior
An ErrorResponse that identifies the timeout before the connection is closed — ideally
matching PostgreSQL:
```
FATAL: 25P03: terminating connection due to idle-in-transaction timeout
```
(The same review may want to cover `idle_in_session_timeout` / `idle_session_timeout`,
which PostgreSQL reports as `57P05`.)
## Environment
- CockroachDB v25.4.14 (also relevant to v25.4.10 in our production fleet)
- Clients tested: psycopg 3.x, pgjdbc 42.7.8 / 42.7.10 (Spring JDBC 6.2.18 + HikariCP),
`cockroach sql` CLI
- Server: single-node insecure docker cluster (behavior is not deployment-specific)
## Additional context
The timeout is implemented as an `AfterFunc` that cancels the session
(`pkg/sql/conn_executor.go`, `IdleInTransactionSessionTimeout`); the client-visible error is
the pgwire read-deadline `i/o timeout` rather than an error constructed for the event. Found
no existing issue mentioning 25P03 or the error surfaced by this timeout.
Jira issue: CRDB-67263
Epic CRDB-65516
Contributor guide
Research direction
Reproduce the timeout with the psycopg example, then inspect pkg/sql/conn_executor.go around IdleInTransactionSessionTimeout and follow the pgwire path that emits the read-deadline error. The fix should send an ErrorResponse identifying the intentional idle-in-transaction timeout with SQLSTATE 25P03 before closing the connection, while considering the related idle-session timeout behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, sql
- Domain
- database
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 57/100