Frequent ECONNRESET on large-context Opus 5 (1M) sessions — RSTs originate from server edge, with SACK gaps on upload
Frequent ECONNRESET on large-context Opus 5 (1M) sessions — RSTs originate from the server edge, with SACK gaps on upload
Summary
Persistent Connection dropped (ECONNRESET) · Retrying in Ns · attempt N/10 banners in Claude Code sessions running Opus 5 with the 1M context window. Packet capture shows the RSTs are sent by the server edge, not by the local network, and several of them carry SACK blocks indicating the server was missing multi-segment runs of the uploaded request body.
Retries usually recover, so hard failures are rare in the transcript — but the retry banners are frequent enough to disrupt work, and each one stalls the session for 2–20s.
Environment
- Claude Code 2.1.234, macOS (Darwin 25.5.0), Node v25.6.0
- Model:
claude-opus-5[1m](1M context) - Affected sessions running at ~420k–457k tokens of context
- Client located in South America; endpoint
160.79.104.10resolves ~16 ms / 6 hops away (CDN edge PoP) - Protocol negotiated: HTTP/2
What the packet capture shows
sudo tcpdump -lni any -vv '(tcp[tcpflags] & tcp-rst != 0) or (ip6 and tcp and ip6[53] & 4 != 0)'
Over a ~2 minute window, deduplicated by 5-tuple + seq:
| Direction | Unique RSTs | TTL |
|---|---|---|
| 160.79.104.10:443 → client | ~69 | 58 |
| client → 160.79.104.10:443 | 13 | 64 |
41 distinct connections were reset by the server in those two minutes.
TTL 58 with a 6-hop path (64 − 6 = 58) places the RST origin at the destination edge, not at any local or ISP device.
SACK evidence of lost upload segments
Four of the server-originated RSTs arrived as [R.] carrying SACK blocks:
17:35:35.742069 160.79.104.10.443 > client.56405: Flags [R.],
options [nop,nop,TS val 3957689344 ecr 99375963,nop,nop,
sack 3 {1654801:1702769}{1610001:1615601}{1584801:1608601}]
Reconstructed gaps in what the server received from the client:
| Time | Missing byte ranges | In units of 1400-byte MSS |
|---|---|---|
| 17:35:35 | 1400, 39200 | 1 seg, 28 segs |
| 17:36:00 | 1400, 19600 | 1 seg, 14 segs |
| 17:36:16 | 5600, 40600 | 4 segs, 29 segs |
| 17:36:38 | 1400, 1400 | 1 seg, 1 seg |
Sequence space in flight at those moments: 370 KB – 1.7 MB, consistent with large request bodies from a 400k+ token context.
The losses are runs of consecutive segments, not isolated drops — a tail-drop signature. Rather than waiting for retransmission, the connection is reset.
Local network ruled out
All measured from the affected machine:
- Packet loss to router, ISP CGNAT, and all internal hops: 0% (25 probes each)
- Bandwidth: ~100 Mbps down / ~63 Mbps up, stable; 6 concurrent 12 MB uploads all completed
- Idle timeout: TLS connections to
api.anthropic.comsurvive 420s of total silence (tested 45/90/150/210/300/420s, with and without SO_KEEPALIVE) - IPv4 vs IPv6 under load: 0/30 failures each
- No proxy, no VPN, MTU 1500, no
NODE_EXTRA_CA_CERTSor related env overrides - 15/15 consecutive TLS handshakes to the API succeed when tested in isolation
Possible relevance of HTTP/2
Connections negotiate HTTP/2. A single reset TCP connection tears down every multiplexed stream on it at once, so a session running subagents loses the main agent and its subagents together. This matches the observed pattern: the banner appears simultaneously in sessions that have subagents active, and does not correlate with concurrency across separate Claude Code processes.
Reproduction
Not reliably reproducible with synthetic traffic. Every synthetic test above passed. It occurs only with real Claude Code traffic at high context — which points at the combination of large request bodies and whatever the edge does when one loses a burst of segments.
Note on observability
The retry banners are not written to the session transcript. Only the rare exhausted-retry failures appear in ~/.claude/projects/**/*.jsonl. Analyzing transcripts therefore measures a different and much smaller population than what users actually experience. If retry counts were recorded (even as a per-turn tally), this class of issue would be far easier to quantify from the client side.
Separately: /bug itself failed with Couldn't send feedback (couldn't reach the service), which is why this is filed on GitHub.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗