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

Open
#173,964 1 comment 0 reactions 0 assignees View on GitHub
C-bug O-community T-sql-foundations X-blathers-triaged
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.