[BUG] Connection pool reuses sockets past the 400s Cloudflare idle timeout, causing ECONNRESET
Summary
Claude Code keeps HTTP keep-alive sockets in its pool beyond the api.anthropic.com edge
idle timeout of 400 seconds, then writes requests onto sockets the server has already
closed. The result is a steady stream of ECONNRESET errors whose frequency scales with
how long a session has been idle.
Reproduced on two separate machines, both macOS, both consumer networks, no VPN or proxy.
Environment
- Claude Code 2.1.218 (native install), desktop bundle 2.1.237
- macOS 15 (Darwin 25.5.0), Node v24.19.0
- No proxy, no VPN, no security extensions. Wi-Fi 6E at -47 dBm, zero interface errors
- Gateway: TP-Link Deco mesh, single NAT, no CGNAT
Measurements
Across 511 local transcripts: 31,315 assistant turns, 2,109 ECONNRESET events (6.7%).
Reset rate by session idle time before the request:
| Idle before request | Reset rate |
| --- | --- |
| under 10s | 4.2% |
| 10 to 60s | 13.3% |
| 1 to 5 min | 16.3% |
| 5 to 15 min | 42.1% |
The server-side timeout is exactly 400 seconds. Probe connections held idle, half withSO_KEEPALIVE enabled:
300s idle, keepalive off -> ALIVE, reuse OK
300s idle, keepalive ON -> ALIVE, reuse OK
600s idle, keepalive off -> FIN at 400.0s
600s idle, keepalive ON -> FIN at 400.0s
1800s idle, either -> FIN at 400.0s
Staggering connection births by 60s produced deaths staggered by 60s, each at age 400.0s.
That confirms a per-connection idle timer rather than a single edge event.
Host comparison, run simultaneously from one machine:
| Host | Idle timeout |
| --- | --- |
| github.com | 30s |
| www.google.com | 240s |
| cloudflare.com | 400.0s |
| api.anthropic.com | 400.0s |
Per-host values rule out a local middlebox, which would impose one timeout on every flow.cloudflare.com matching api.anthropic.com identifies 400s as the Cloudflare edge
keep-alive timeout.
Why this points at the client
Closing idle keep-alive connections is correct server behavior. The defect is that the pool
holds sockets past that boundary and reuses them without revalidation. During this
investigation the client held 90 established connections to 160.79.104.10, so a large
fraction of the pool can be older than 400s at any moment.
Retry behavior fits a pool of dead sockets rather than a transient network fault. The
conditional probability that a retry also fails rises with attempt count, from 0.56 at
attempt 2 to 0.83 by attempt 10, consistent with successive retries drawing further stale
sockets from the same pool. Of roughly 710 affected requests, 49 exhausted all 10 retries.
Suggested fix
Set the agent's free-socket idle timeout below the edge timeout so the client discards
sockets before the server does. 240s would leave headroom under 400s. Retrying idempotent
requests once on a reset from a reused socket is the standard remedy for this race.
Workaround in use
CLAUDE_CODE_MAX_RETRIES=20 via settings.json, which masks the symptom and adds about
6 minutes before a doomed request surfaces. No client setting exists for pool or keepalive
tuning, so the cause is not addressable from the user side.
Reproduction
Leave a session idle for 7 to 10 minutes, then send a request. The first request after the
gap resets far more often than one sent during continuous activity.
Related issues
Likely the same root cause: #87424, #81847, #75956, #86632, #87599.
On #87599 specifically: that report rules out an idle timeout on the grounds that resets
arrive in simultaneous bursts of 10 to 15 connections within ~3ms, arguing a per-flow
problem would kill one connection at a time. A connection pool opens its sockets within
milliseconds of each other during parallel work, so a per-connection 400s timer expires
all of them within milliseconds of each other 400 seconds later. The burst pattern is what
a per-connection idle timeout looks like on a pooled connection set, so that evidence
supports the idle-timeout explanation rather than excluding it.
The staggered-birth measurement above was run specifically to separate those two cases.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗