[Bug] Anthropic API Error: ECONNRESET with exhausted retries in Claude desktop app
<html>
<body>
<!--StartFragment--><h2 dir="ltr" class="mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="7:1-7:11;127-137">Summary</h2>
<p class="font-claude-response-body break-words whitespace-normal" dir="ltr" data-sourcepos="9:1-13:57;139-579">Claude Code fails intermittently with <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">API Error: Connection to the API was lost (ECONNRESET)</code>.
In the terminal CLI the built-in retry usually recovers it after ~5 s. In the Claude desktop
app's <strong>Code</strong> surface the retries exhaust far more often and the error is surfaced to the user —
in one case continuously for ~45 minutes, after which queued messages went through and the model
replied, then the next message failed again immediately.</p>
<p class="font-claude-response-body break-words whitespace-normal" dir="ltr" data-sourcepos="15:1-16:99;581-769">Every plausible local cause was tested and excluded. I'm filing this because the existing
ECONNRESET reports mostly lack the negative evidence, and that seems to be what's blocking triage.</p>
<h2 dir="ltr" class="mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="18:1-18:15;771-785">Environment</h2>
<ul dir="ltr" class="[li_&]:mb-0 [li_&]:mt-1 [li_&]:gap-1 [&:not(:last-child)_ul]:pb-1 [&:not(:last-child)_ol]:pb-1 list-disc flex flex-col gap-1 pl-8 mb-3 print:block print:space-y-1" data-sourcepos="20:1-25:57;787-1160">
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="20:1-20:103;787-889"><strong>Claude Code:</strong> 2.1.222 (native install, <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">~/.local/bin</code>) and 2.1.221 (bundled with the desktop app)</li>
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="21:1-21:60;890-949"><strong>Desktop app:</strong> 1.25927.0.0 (MSIX / WindowsApps package)</li>
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="22:1-22:25;950-974"><strong>OS:</strong> Windows 11 x64</li>
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="23:1-23:53;975-1027"><strong>NIC:</strong> Realtek PCIe 2.5GbE, single default route</li>
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="24:1-24:76;1028-1103"><strong>Auth:</strong> claude.ai subscription (OAuth), re-authenticated during testing</li>
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="25:1-25:57;1104-1160"><strong>Connection:</strong> fibre, ~83 Mbit/s down / ~44 Mbit/s up</li>
</ul>
<h2 dir="ltr" class="mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="27:1-27:19;1162-1180">Key observation</h2>
<p class="font-claude-response-body break-words whitespace-normal" dir="ltr" data-sourcepos="29:1-32:73;1182-1546"><strong>Cowork works normally throughout; only Code fails.</strong> Both run from the same desktop app on the
same machine and network. Cowork executes in Anthropic's cloud and only uploads the user's typed
message; Code runs the CLI locally and uploads the full context each turn. Whatever the cause is,
it affects the locally-spawned CLI process and not the app's cloud path.</p>
<h2 dir="ltr" class="mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="34:1-34:34;1548-1581">Ruled out — with the test used</h2>
<div dir="ltr" class="overflow-x-auto w-full px-2 mb-6 print:overflow-x-visible" data-sourcepos="36:1-55:124;1583-3781">
Hypothesis | Test | Result
-- | -- | --
Anthropic outage | status page + HTTP probe from an unrelated cloud host | No open incidents; 8/8 requests, ~50 ms, zero resets
DNS | Resolve-DnsName, curl | Resolves fine, Cloudflare MAD edge
System proxy | netsh winhttp show proxy | Direct access, no proxy
Proxy / override env vars | HTTPS_PROXY, HTTP_PROXY, ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN | All unset
TLS interception (AV / VPN / ZAP root CA) | raw SslStream handshake, inspected issuer | CN=WE1, O=Google Trust Services, C=US — legitimate, no MITM
Node CA bundle mismatch | node -e "fetch('https://api.anthropic.com')" | NODE OK 404
VPN interference | Get-NetAdapter | No VPN adapter up
MTU / PMTU blackhole | Get-NetIPInterface | 1500 on every connected interface
IPv6 / broken PMTUD over v6 | Get-NetIPInterface | No IPv6 on any real adapter (loopback only)
Large download failure | 20 MB from Cloudflare, default and -4 | bytes=20000000 code=200 t=1.92s
Large upload burst overflowing an upstream buffer | POST 1/2/3/5/10 MB to speed.cloudflare.com/__up | All 200, linear, 10 MB in 1.90 s, no degradation
Asymmetric routing (two NICs up) | Get-NetRoute -DestinationPrefix 0.0.0.0/0 | Single default route; the second adapter is VirtualBox Host-Only with no route
Windows Firewall | Get-NetFirewallApplicationFilter, Get-NetFirewallProfile | All claude.exe rules are Allow; DefaultOutboundAction is NotConfigured (= allow) on all profiles
Outdated client | claude --version / claude update | 2.1.90 → 2.1.222; the app-bundled CLI was already 2.1.221
Orphaned CLI processes | Get-CimInstance Win32_Process | One CLI process (killed); the other 13 are Electron desktop-app processes
Broken OAuth token | claude doctor flagged a missing user:profile scope | auth logout + auth login → Login successful. Error persisted.
Workspace / context size | claude -p in an empty directory | Fails identically outside the large repo
SessionStart hook injecting a large context | ran the hook script directly | 7,349 characters (~2k tokens) — negligible
</div>
<h2 dir="ltr" class="mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="57:1-57:16;3783-3798">Reproduction</h2>
<p class="font-claude-response-body break-words whitespace-normal" dir="ltr" data-sourcepos="59:1-60:86;3800-3984">Not deterministic. Typically on the first request of a session and intermittently after. The CLI's
automatic retry masks it most of the time; the desktop app's Code surface exposes it.</p>
<h2 dir="ltr" class="mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="62:1-62:26;3986-4011">Two secondary findings</h2>
<ol dir="ltr" class="[li_&]:mb-0 [li_&]:mt-1 [li_&]:gap-1 [&:not(:last-child)_ul]:pb-1 [&:not(:last-child)_ol]:pb-1 list-decimal flex flex-col gap-1 pl-8 mb-3 print:block print:space-y-1" data-sourcepos="64:1-69:56;4013-4422">
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="64:1-66:59;4013-4269"><code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">statsig.anthropic.com</code> fails a TCP/443 reachability test while every other Anthropic and Claude
host succeeds from the same machine. The CLI works regardless, so it appears non-fatal, but it
may be worth confirming the client doesn't block on it.</li>
<li class="font-claude-response-body whitespace-normal break-words pl-2" data-sourcepos="68:1-69:56;4271-4422"><strong>Separate, reproducible bug:</strong> hook commands in <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">settings.json</code> lose their backslashes when
handed to the shell, because the path is not quoted.</li>
</ol>
<div role="group" aria-label="Código" tabindex="0" data-sourcepos="71:1-74:4;4424-4623" class="relative group/copy bg-bg-000/50 border-0.5 border-border-400 rounded-lg focus:outline-none focus-visible:ring-2 focus-visible:ring-accent-100"><div class="sticky opacity-0 group-hover/copy:opacity-100 group-focus-within/copy:opacity-100 top-2 py-2 h-12 w-0 float-right"><div class="absolute right-0 h-8 px-2 items-center inline-flex z-10"></div></div><div class="overflow-x-auto"><pre class="code-block__code !my-0 !rounded-lg !text-sm !leading-relaxed p-3.5" style="color: rgb(234, 236, 240); background: transparent; font-family: var(--font-mono);"><code style="color: rgb(234, 236, 240); background: transparent; font-family: var(--font-mono); white-space: pre-wrap;"> SessionEnd hook [powershell -ExecutionPolicy Bypass -NoProfile -File C:\Users\X\.claude\hooks\a.ps1] failed:
The argument 'C:UsersX.claudehooksa.ps1' for parameter -File does not exist.</code></pre></div></div>
<p class="font-claude-response-body break-words whitespace-normal" dir="ltr" data-sourcepos="76:4-79:96;4628-5011"><code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">C:\Users\X\.claude\hooks\a.ps1</code> arrives as <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">C:UsersX.claudehooksa.ps1</code>. The JSON is correctly
escaped (<code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">C:\\Users\\...</code>); the stripping happens after parsing. <code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">permissions.allow</code> entries in
the same file quote their paths and are unaffected. Workaround: quote the path in the hook
command, or use forward slashes. Windows hook paths arguably should be quoted by the client.</p>
<h2 dir="ltr" class="mt-3 -mb-1 text-[1.125rem] font-bold" data-sourcepos="81:1-81:21;5013-5033">Workaround in use</h2>
<p class="font-claude-response-body break-words whitespace-normal" dir="ltr" data-sourcepos="83:1-83:59;5035-5093"><code class="bg-text-200/5 border border-0.5 border-border-300 text-danger-000 whitespace-pre-wrap rounded-[0.4rem] px-1 py-px text-[0.9rem]">CLAUDE_CODE_MAX_RETRIES=20</code> (raised from the default 10).</p>
<p class="font-claude-response-body break-words whitespace-normal" dir="ltr" data-sourcepos="85:1-86:94;5095-5287">Note that once the client is stuck in the retry loop it does <strong>not</strong> recover on its own even after
connectivity is independently confirmed healthy — the process has to be killed and restarted.</p><!--EndFragment-->
</body>
</html>
Showing cached comments. Read the full discussion on GitHub ↗
4 Comments
Same desktop app build — 1.25927.0.0 (MSIX / WindowsApps), Windows, bundled CLI 2.1.221. Started 5 August. Two things differ from the original report, and I have two additional findings that may point at the cause.
1. Both surfaces fail, not just Code
Cowork and the Code panel both fail on every request, including a one-word "hello". Chat mode in the same app works normally. Claude Code via the PyCharm plugin — same machine, same account, same network — works normally throughout.
2. Time to failure is constant
| seconds_to_outcome | model | effort | MCP servers |
|---|---|---|---|
| 203 | claude-sonnet-5 | high | 30 |
| 210 | opus-5 | high | 30 |
| 213 | opus-5 | high | 10 (all plugins/skills disabled) |
Independent of model, thinking effort, MCP server count and context size. That reads as a fixed timeout rather than capacity degradation or retry exhaustion.
The UI error text is misleading
Surfaced message is "Connection to the API was lost (ECONNRESET)", but the logged SDK error is
server_error:No ECONNRESET appears anywhere in main.log except inside that error_message string — worth fixing on its own, since it sends users chasing network causes.
had_first_response: true: the model starts responding, then the turn dies at the timeout. 47 KB transcript on a fresh session, so context size is not a factor.Finding A — statsig.anthropic.com unreachable (second confirmation)
Test-NetConnection statsig.anthropic.com -Port 443fails whileapi.anthropic.comsucceeds from the same machine. That matches the original report's secondary finding, now seen independently on a second Windows machine on a different network.Finding B — experiment gate variant
The CycleHealth block carries
variant_key: '06_22_2026.replace'. Since Statsig also serves client-side experiment gates, a bad variant would explain why users on the identical build see different behaviour, and why Chat and the CLI — which take different paths — are unaffected. Might be worth checking which cohort the affected sessions land in.Ruled out here, beyond the original table
Reproduced on a mobile hotspot with no VPN (different network, different NAT). Full uninstall and reinstall of the app. CoworkVMService running continuously, no restarts, no SCM 7031/7034 events. No web connectors connected. All plugins and skills disabled (MCP servers 30 → 10, no change).
[VM] API reachability: REACHABLE, VM startup ~5 s.Related
#68092 (macOS) has a near-identical CycleHealth shape —
had_first_response: true,seconds_to_outcome: 186,is_resume: false,api_error, hotspot tested, clean reinstall survived — so this does not look platform-specific. #67091 proposes a missing SO_KEEPALIVE on the API sockets at ~346 s; my figure is consistently ~205 s and reproduces across networks, so if it is the same root cause the timeout value comes from somewhere other than router NAT.I can confirm the same failure pattern, with an even broader set of negative results.
Environment
Windows 11, subscription account, tested on both a workplace network and a home network, and via VPN (no difference across any of them). Both the desktop app's Code surface and the standalone CLI are affected.
Symptom
API Error: Connection to the API was lost (ECONNRESET), and occasionallyConnection closed mid-responsewhen connected via VPN. Retries exhaust intermittently (observed up to attempt 13-15 of 15).Ruled out today, in addition to what's already listed above:
curl -vto/v1/messagescompletes the TLS handshake and gets a correct response from Cloudflare (401/405 as expected); only persistent/streaming connections fail~/.claude/hooksdisabledNotable
Not the account, not the network, not endpoint security, not project configuration, not global hooks or skills, and not the CLI version. Given how much has been excluded here and in the original report, this looks increasingly like a server-side or protocol-level issue specific to the long-lived/streaming connection Claude Code uses, rather than anything client-environment-specific.
Current workaround
CLAUDE_CODE_MAX_RETRIES=20. Still experiencing intermittent failures throughout the day (JST, Aug 6–7 2026).Re: the statsig.anthropic.com finding above — third independent confirmation, and one step further
On my machine,
statsig.anthropic.comfails at DNS resolution itself, not just at the TCP/443 stage:For contrast,
api.anthropic.comresolves and connects normally on the same machine/network:So this is now reproduced on a third independent machine/network, and in my case the failure is even earlier in the connection process (DNS, not just the socket). This seems like a strong lead — worth checking whether the client blocks or degrades gracefully when statsig is unreachable.
Same symptom, same platform. I can add the piece your elimination table couldn't cover: a version bisect. On my machine this is a regression, and the window is a single release.
2.1.220is clean.2.1.221fails ~50% of the time.2.1.222did not fix it — same ~50%.---
Version bisect
Both binaries invoked from the same PowerShell session, interleaved within each iteration so any drift in conditions hits both arms equally:
| Version | Trials | OK | Failed | Notes |
|---|---|---|---|---|
| 2.1.219 | 30 | 30 | 0 | 10 on default model + 20 on Haiku 4.5 |
| 2.1.220 | 10 | 10 | 0 | Haiku 4.5 |
| 2.1.221 | 30 | 15 | 15 (50%) | 10 on default model + 20 on Haiku 4.5 |
| 2.1.222 | loop-tested | — | ~50% | Same failure rate and same error strings as 221; raw output not retained |
40/40 clean across 219 and 220. Both 221 and 222 fail at ~50%.
The regression appears at 220 → 221 and is still present in 222.
| Run | Date | Model | Versions compared |
|---|---|---|---|
| 1 | 2026-08-06 | default | 219 vs 221 — 10/10 vs 5/10 |
| 2 | 2026-08-06 |
claude-haiku-4-5-20251001| 219 vs 221 — 20/20 vs 10/20 || 3 | 2026-08-08 |
claude-haiku-4-5-20251001| 220 — 10/10 || 4 | 2026-08-08 |
claude-haiku-4-5-20251001| 222 — ~50% failures (raw output not retained) |Explicitly pinning the model made no difference to the failure rate, so this isn't model- or routing-related.
Two distinct failure modes from 221
Roughly 11 / 4 across the 15 failures. The second form is the informative one — a complete, well-formed response arrives and the error is appended after it. The content was delivered; the stream didn't terminate cleanly. That points at connection/stream teardown rather than transport.
<details>
<summary>Run 2 raw output — 20 rounds, Haiku 4.5, interleaved</summary>
</details>
---
This isn't context size or the desktop app
Worth stating explicitly, since it narrows things further:
-p ping). It still fails at ~50% on 221.---
End-to-end confirmation in the desktop app
Not just a CLI result. I forced the app onto a known-good binary by moving the bad version out of the tree and replacing it with a junction:
The Code tab worked immediately and stayed stable. Same app build, same session weight, same 9 MCP servers, same account — only the binary underneath changed. I've now done this twice: pinned to 219 on Aug 5, then to 220 today after the app auto-updated to 222.
Two practical notes for anyone reproducing this
Binary selection appears to enumerate the directory rather than resolve an exact version. My first attempt renamed
2.1.221→2.1.221.brokenin place and put the junction beside it. The app loaded the renamed folder anyway:The bad build has to leave the directory entirely. This also means any local pin is silently superseded on the next auto-update.
The npm platform packages are versioned independently of the wrapper.
npm pack @anthropic-ai/claude-code@2.1.219yields a platform binary that reports2.1.220. Useful to know if you're trying to obtain a specific older build — check what you actually got with--versionbefore relying on it.---
What the app records
From the session JSONL:
"rateLimits": nullwith no status code — no HTTP response was received at all, so this isn't a 429/529 surfacing as a connection error.isSSLError: falserules out certificate rejection.---
Ruled out on my side
Complementing your table:
| Hypothesis | Test | Result |
|---|---|---|
| Auth / token | app log OAuth lookup; chat tab | Lookup succeeds; chat works throughout |
| Binary fails to spawn | app log session lifecycle | Warms in 135 ms, PTY starts, CLI session ID mapped |
| Non-ASCII cwd | repeated in a pure-ASCII path | Fails identically |
| Anthropic incident | repeated across three days | 219/220 never fail; 221 fails on every day tested |
| MTU / payload size | POSTs of 1 / 50 / 200 / 800 KB | All return
401— full body reaches the API || Network instability | 20×
curltoapi.anthropic.com| 20/20, 520–880 ms, zero timeouts || VPN on/off | toggled | No change |
| VPN exit node | switched | No change |
| VPN client version | updated | No change |
| Split tunnelling | Claude never in the list | Not applicable |
| Model | explicit
claude-haiku-4-5-20251001| Same ~50% |---
Possibly relevant
The
2.1.221release notes mention changes to MCP connection handling in print mode (-p) — servers from--mcp-confignot being connected before the first turn — plus MCP connect behaviour and sandbox proxy TLS handling. My repro is-pmode. That may be coincidence, but 220 → 221 is now a single release to bisect.Worth noting the regression survived a subsequent release. Whatever changed in 221 is still there in 222, so this isn't a one-off bad publish that has since been superseded.
Also possibly related: #67766, where packet captures across ten incidents showed clean server-initiated FIN mid-stream — never an RST, never a client-side close — with the request body fully acknowledged seconds earlier and a fresh connection succeeding immediately afterward. That reporter noted the CLI's retry sometimes recovered the turn and sometimes didn't, depending on where in the turn the FIN landed. If the server closes are pre-existing, then what changed in 221 is the client's ability to recover from them.
---
Caveats
2.1.222's raw output wasn't retained — the loop showed the same ~50% failure rate and the same error strings---
Workaround
Pinning the app-bundled binary to
2.1.220or2.1.219eliminates the failures here rather than mitigating them — worth trying alongsideCLAUDE_CODE_MAX_RETRIES=20, given the note that the client doesn't self-recover once the retry loop is exhausted.Environment
~/.local/bin/claude) — also reproduces in the Claude Desktop app's bundled Code surfaceSymptom
Non-trivial Code requests fail with:
API Error: Connection to the API was lost (ECONNRESET)/Connection closed mid-response. The response above may be incomplete.The connection establishes and the session runs for a while (I've seen "Baked for 3m 35s" and "Baked for 13m 27s") before the socket is reset mid-response. Automatic retries (
attempt X/10) also fail. curl and the regular chat succeed on the same machine/network at the same time.Key discriminator
Regular Claude chat in the same Desktop app works perfectly — only the Code surface (the locally-spawned CLI process) fails. It reproduces identically on the standalone CLI (2.1.226) and on the Desktop app's bundled Code, which share the same user config dir. So it's neither the binary version nor the account.
Onset
Started right after leaving a Code session running overnight, which crashed with a Windows "file already in use" error attributed to Claude. Broken on every request since, and persists across reboots.
Tested and eliminated (all performed; ECONNRESET persisted after each)
curl -I https://api.anthropic.comreturns HTTP 404 from the Cloudflare edge on both IPv4 (-4) and IPv6 (-6).ping 8.8.8.8 -f -l 1472succeeds (1500 intact); forcing the interface MTU to 1492 had no effect.HTTP_PROXY/HTTPS_PROXY/ANTHROPIC_*env vars;~/.claude/settings.jsonclean.~/.claude.jsonand~/.claude, re-logged in — no effect.--strict-mcp-config --mcp-config(servers reduced) — still resets. The reset is on the main API connection, not on an MCP server.This matches #62045 (Windows + Realtek, network verified healthy, only the Claude Code client resets) and the negative-evidence report in #83994.