Intermittent ECONNRESET / Connection error on /v1/messages — auth OK, transport-level reset, 3 macOS machines
Summary
Persistent intermittent ECONNRESET / "Connection error" on /v1/messages across 3 macOS machines (2× headless Mac mini + 1× MacBook Air), all logged into the same account. A 4th machine (Windows PC) on the same network/WiFi does not exhibit it. The errors are transport-level (auth succeeds on every attempt), so this appears to be a server/edge connection issue rather than a client auth or local network problem.
Symptom
On each failing request:
[API:auth] OAuth token check starting→complete— succeeds every time (not auth-related)[API REQUEST] /v1/messages ...dispatched- ~40ms later:
[ERROR] API error (attempt N/16): undefined Connection error. - Final:
code=ECONNRESET, message=The socket connection was closed unexpectedly
Retries eventually recover, but bursts can exhaust the retry budget and abort the turn.
What we ruled out (with evidence)
- Not auth / token: OAuth token check completes successfully on every single attempt across all logs.
- Not local network: single
curl(both IPv4 and IPv6) toapi.anthropic.comfrom an affected machine succeeds 20/20, fast TLS handshake. - Not egress path: routing one affected machine's traffic through a separate SSH SOCKS5 tunnel (different egress IP) did not stop the resets.
- Not multi-device credential race: each machine has its own independent local
.credentials.json(separate files, separate disks, no shared/networked storage).
Environment
- Client versions observed:
2.1.199,2.1.196,2.1.179 CLAUDE_CODE_RETRY_WATCHDOG=1andCLAUDE_CODE_MAX_RETRIES=15are set and confirmed active (retry counter shows/16)- macOS (Apple Silicon), installed via Homebrew cask; Windows PC unaffected
- Model:
claude-opus-4-8[1m]
x-client-request-id samples for server-log lookup
40bad3a9-c066-4e2a-8bf5-5ad34846cc0e(client flagged this one as "give this to the API team for server-log lookup")cebf6335-0267-4259-81c4-9d8652d40c74a748c52a-58ea-4b23-b493-dd83da11e82b23efc0a0-40e1-4f11-b954-5171f5bc16adfbd1203c-dded-4b1f-baf0-c3defaa89659850cd93f-014c-4db6-a365-0c498f2fb7eb
Timestamps: 2026-07-03 05:27–05:30 UTC and 07:14–07:15 UTC.
Source contexts: repl_main_thread and away_summary (forked agent).
Question
Can the team look up these request IDs server-side to determine where the connection is being reset (edge/LB/backend)? Happy to provide full debug logs.
3 Comments
Root cause found — IPv4 edge resets requests with body ≥ ~2KB; IPv6 edge is fine
Reproduced deterministically on an affected machine (macOS, Apple Silicon). The ECONNRESET is not auth, token, MTU-in-general, or a local proxy — it is specific to the IPv4 edge of
api.anthropic.comresetting POST requests once the request body exceeds ~1 TCP segment (~2KB).Evidence
Current DNS for
api.anthropic.com:160.79.104.102607:6bc0::10Large POST (500KB body) to
/v1/messages, 10 iterations each:| Path | Result |
|------|--------|
| IPv4
160.79.104.10| reset 10/10 (curlexit 56 / ECONNRESET, ~40ms) || IPv6
2607:6bc0::10| 200/401 OK 10/10 |Body-size threshold sweep over IPv4 (5x each):
curl -von the failing IPv4 request shows: TCP connects to160.79.104.10:443, TLSv1.3 handshake completes, HTTP/2 stream opens,:method: POSTis sent, then the connection is reset as the body is transmitted. Cert validates (real edge, no MITM).What it is NOT
www.google.com(405) andcloudflare.com(301) succeed fine at the same time.rdrrules for :443;curlconnects directly to the real edge IP with a valid cert.Why it manifests as intermittent ECONNRESET in the client
Real Claude Code requests always carry >2KB (system prompt + tool defs + context), so they always exceed the threshold. The bundled runtime's Happy Eyeballs selects IPv4 because the IPv4 TCP connect succeeds (and TLS completes) — the reset only happens later when the request body is sent — so the client keeps choosing the broken path and dies mid-request. A Windows machine on the same network/WiFi is unaffected (appears to use IPv6 / a different edge).
Simple client-side IPv6 forcing does not stick: an
/etc/hostsAAAA entry gets merged with the DNS A record, and--dns-result-order=ipv6firstis not honored byfetch, so the runtime still picks the IPv4 edge.Ask
Please investigate the IPv4 edge
160.79.104.10(and the surrounding prefix) resetting/v1/messagesPOST requests whose body exceeds ~1 segment. This may be a broken edge node or a path/MTU issue on the IPv4 prefix. Happy to run any further diagnostics or provide packet captures.Follow-up: IPv6 workaround confirmed end-to-end + cross-platform data point
Workaround verified. On all three affected macOS machines, forcing traffic onto IPv6 (blackholing Anthropic's IPv4
/21with a reject route so the client falls back to IPv6) makes realclaude -prequests succeed reliably — no ECONNRESET, no retries. This confirms the failure is on the IPv4 path/edge specifically, not the client or general connectivity.Cross-platform observation (may help localize it). A Windows 11 machine on the same LAN / same router / same ISP, reaching the same IPv4 edge
160.79.104.10directly (no VPN, source on the same subnet), does NOT reproduce the reset — large IPv4 POSTs return 401 normally, 5/5. The three macOS machines on that identical path reset 100% of the time on the same request.So on one physical network:
160.79.104.10= reset (after TLS+HTTP/2, as body is sent)160.79.104.10= works2607:6bc0::10= worksSame path, same destination, differs only by client OS. This points to the IPv4 edge (or a middlebox on the path to it) mishandling something specific to macOS's large TCP segments / full-MTU packets rather than a plain edge outage. Windows likely also uses IPv6 preferentially, which is why users on Windows see this only rarely.
Happy to provide a
pcapfrom a resetting macOS request vs a working Windows one if that helps.Another affected setup, with request IDs for the server-side lookup this issue asks for — plus evidence that the failing requests hit a warm prompt cache, which rules out the cold-cache mechanism proposed in #79989 / #74544.
Same symptom as reported here: intermittent
API Error: Unable to connect to API (ECONNRESET), transport-level, macOS, auth fine throughout, retries exhaust and abort the turn.One difference worth stating up front: this issue's onset is 2026-07-03 on CC 2.1.179–2.1.199, mine is 2026-07-23 on 2.1.217–2.1.220. Same signature, later onset — so either it's long-lived and intermittent per-account, or these are two instances of the same edge behavior.
Scope
21 ECONNRESET events (filtered on Claude Code's
isApiErrorMessageflag — a naive grep over transcripts inflates the count, because diagnostic sessions echo the string into their own logs) out of 15,976 API requests across 6 projects, 2026-07-07 → 2026-07-27, all counted by one script.Still occurring as of today.
Key finding: the prompt cache was warm on every failure
| timestamp (UTC) | CC ver | model | cache_read | total ctx | cache share | last successful
requestId||---|---|---|---|---|---|---|
| 2026-07-23T22:59:49 | 2.1.217 | claude-fable-5 | 271,765 | 272,762 | 99.6% |
req_011CdKp27ZPZPeVkco4iC7Gk|| 2026-07-23T23:35:34 | 2.1.217 | claude-fable-5 | 312,357 | 315,398 | 99.0% |
req_011CdKrhnXFviRAMkGYvQ6N2|| 2026-07-24T21:44:17 | 2.1.218 | claude-fable-5 | 494,119 | 501,807 | 98.5% |
req_011CdMbxEyss4TG7gw87Xf12|| 2026-07-25T02:12:22 | 2.1.218 | claude-opus-4-8 | 189,260 | 194,868 | 97.1% |
req_011CdMxXHQUj2Cv3X9DZK3SX|| 2026-07-25T02:47:49 | 2.1.220 | claude-opus-5 | 107,740 | 108,729 | 99.1% |
req_011CdN1DBpU2nvV31AcoKyQd|| 2026-07-25T03:08:47 | 2.1.220 | claude-opus-5 | 136,792 | 137,087 | 99.8% |
req_011CdN2pGWqjFFGst3qKEX5S|| 2026-07-26T18:57:04 | 2.1.220 | claude-opus-5 | 553,882 | 556,964 | 99.4% |
req_011CdRAwB2L73nGdGmiriyJz|| 2026-07-27T02:05:16 | 2.1.220 | claude-opus-5 | 524,722 | 525,142 | 99.9% |
req_011CdRjWyp4VFAPFPwxLpTxM|requestIdis from the last successful request immediately before each failure — the reset request itself never returns an ID. The failing request is the next one in the same conversation, ~6 minutes later.On every failure that preceding request read 97.1%–99.9% of its context from cache, with
input_tokens: 2andcache_creation_input_tokensof only 293–7,686. The failing request therefore put a few KB of new tokens on the wire against a warm cache — not a large uncached re-ingestion.That's the substantive disconfirmation of #79989's mechanism ("the first fully-uncached replay of a big context is what fails"). Here the cache is warm, the incremental payload is tiny, and the resets land mid-conversation during continuous work rather than after an idle gap.
On the >200k threshold claim
#79989 states "every observed failure is >200k and we have never observed a failure ≤200k". Two of mine are below that in live context size — 108,729 and 137,087 tokens — plus one at 194,868.
Stated precisely, because it matters: Claude Code's transcript
usageentries record the base model ID with any[1m]suffix stripped, so I cannot tell from my logs whether the 1M-context beta header was set on those requests. Other sessions in the same account reached 501k–557k, so the beta is clearly in use on this account generally. A "those were on the long-context path regardless of size" reading is not excluded by my data. I'd treat the size counterexamples as suggestive only — the cache warmth, not the size, is what actually contradicts the proposed mechanism.Retry budget: fixed ~350s wall clock, independent of payload
Measured from the user's prompt to the surfaced error (not from the previous assistant turn, so it excludes think time):
Every failure aborts 5.7–6.3 minutes after the prompt is sent, and the spread is the same at 108k context as at 557k. So the retry window is bounded by wall clock, not by payload size or attempt cost.
What does not correlate: session age
I checked this because "long-running sessions" was my initial hypothesis, and my own logs don't support it. Session age at failure:
Two failures landed 12 and 36 minutes into a fresh session. Meanwhile 59.7% of all 15,976 successful requests were issued at a session age above the minimum failing age, and successful requests run out to a 59.4h session age. Session longevity is not the driver — posting the negative result so nobody else chases it.
Context size doesn't separate the groups either: failures span 108k–557k, while the median across all requests is 321,774 tokens (p90 772,398, max 1,793,423). Far larger requests succeed routinely.
Environment
claude-fable-5,claude-opus-4-8,claude-opus-5— all three affectedANTHROPIC_BASE_URL, no proxy (scutil --proxyempty), direct Wi-Fi to gateway. Tailscale installed but not on the API path, no exit node.Ruled out locally, with evidence
/usr/bin/log showacross the error window: zeroLinkDown, zero link-quality-degraded, zeronw_path unsatisfied, covering 10 of the error moments. Retention verified by narrow probes at each moment returning 30k–63k real log lines, so the zero isn't vacuous. (An earlier "no flaps" result in my own notes was withdrawn and re-run —loghad been shadowed by a shell function and silently returned nothing.)netstat -s: 0 bad resets, 0 retransmit-timeout drops, 0 keepalive-timeout drops in 53 days of uptime.Ask
Same as the original request in this issue: can someone look up those request IDs server-side and identify where the connection is being reset — edge, LB, or backend? Each listed ID is the last successful request in its conversation; the reset is on the immediately following request in the same session, within ~6 minutes.
Happy to provide full transcripts or run instrumented captures.