[Bug] Anthropic API Error: ECONNRESET with exhausted retries in Claude desktop app

Status Open
Reported on v2.1.222
Maintainer reply None cached
Activity 12 comments · opened Aug 5, 2026

<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_&amp;]:mb-0 [li_&amp;]:mt-1 [li_&amp;]:gap-1 [&amp;:not(:last-child)_ul]:pb-1 [&amp;: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_&amp;]:mb-0 [li_&amp;]:mt-1 [li_&amp;]:gap-1 [&amp;:not(:last-child)_ul]:pb-1 [&amp;: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>

View original on GitHub ↗

4 Comments

SkeiLeinux · 24 days ago

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:

[APIError] Intermediate SDK error "server_error" for session local_f53b3b5b-... — continuing to read stream
[Result] Turn failed for session local_f53b3b5b-...: subtype=success, is_error=true
[CycleHealth] Unhealthy cycle: {
  model: 'claude-sonnet-5',
  effort: 'high',
  maxThinkingTokens: 31999,
  host_loop_mode: true,
  variant_key: '06_22_2026.replace',
  cycle_health: 'unhealthy',
  had_first_response: true,
  seconds_to_outcome: 203,
  is_resume: false,
  unhealthy_reason: 'api_error',
  error_message: 'API Error: Connection to the API was lost (ECONNRESET). This is usually temporary — try again.',
  transcript_size_bytes: 47849
}

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 443 fails while api.anthropic.com succeeds 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.

onoenoe · 23 days ago

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 occasionally Connection closed mid-response when 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:

  • Home network / ISP — reproduces on home network too, unrelated to any corporate infra
  • VPN on/off — reproduces both ways (different error message depending on state)
  • Endpoint security (ESET) — SSL/TLS filtering, IDS, botnet protection, and firewall all disabled — no change
  • Single-request connectivitycurl -v to /v1/messages completes the TLS handshake and gets a correct response from Cloudflare (401/405 as expected); only persistent/streaming connections fail
  • Project-specific config — hooks, MCP servers, skills, agents, large context — reproduces in a completely empty project directory
  • Global hooks and large custom setup — 260+ skills, 38 agents, 80+ MCP tools — reproduces even with ~/.claude/hooks disabled
  • A failing MCP server — disabled it, no change
  • CLI version — reproduces on 2.1.223, 2.1.224, and after downgrading to 2.1.126
  • Account — switched to a different account entirely, reproduces on both
  • Multiple users — reproducing independently on separate machines and networks, not isolated to one person

Notable

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.com fails at DNS resolution itself, not just at the TCP/443 stage:

PS> Test-NetConnection statsig.anthropic.com -Port 443
Name resolution of statsig.anthropic.com failed
PingSucceeded : False

For contrast, api.anthropic.com resolves and connects normally on the same machine/network:

PS> Test-NetConnection api.anthropic.com -Port 443
TcpTestSucceeded : True

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.

petuh-ys · 22 days ago

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.220 is clean. 2.1.221 fails ~50% of the time. 2.1.222 did 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:

1..N | % {
  "A -> $(& $binA -p ping 2>&1)"
  "B -> $(& $binB -p ping 2>&1)"
}

| 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

API Error: Connection to the API was lost (ECONNRESET). This is usually temporary — try again.
Pong! I'm here and ready to help. What would you like to work on? API Error: Connection closed mid-response. The response above may be incomplete.

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>

219 -> Pong! I'm here and ready to help. What would you like to work on?
221 -> API Error: Connection to the API was lost (ECONNRESET). This is usually temporary — try again.
219 -> Pong. Ready to help—what's up?
221 -> Pong! I'm ready to help. What would you like to work on?
219 -> Pong! I'm ready to help. What would you like to work on?
221 -> Pong! I'm ready to help. What would you like to work on?
219 -> Pong! I'm ready to help. What would you like to work on?
221 -> Pong! I'm ready to help. What would you like to work on?
219 -> Pong! 👋 I'm ready to help. What would you like to work on?
221 -> API Error: Connection to the API was lost (ECONNRESET). This is usually temporary — try again.
219 -> Pong! I'm ready to help. What would you like to work on?
221 -> Pong! 👋 I'm here and ready to help. What can I do for you?
219 -> Pong! I'm here and ready to help. What would you like to work on?
221 -> API Error: Connection to the API was lost (ECONNRESET). This is usually temporary — try again.
219 -> Pong! I'm here and ready to help. What would you like to work on?
221 -> API Error: Connection to the API was lost (ECONNRESET). This is usually temporary — try again.
219 -> Pong! I'm here and ready to help. What can I do for you?
221 -> Pong! I'm ready to help. What would you like to work on?
219 -> Pong! I'm here and ready to help. What can I do for you?
221 -> API Error: Connection to the API was lost (ECONNRESET). This is usually temporary — try again.
219 -> Pong! I'm here and ready to help. What would you like to work on?
221 -> API Error: Connection closed mid-response. The response above may be incomplete.
219 -> pong 👋 Ready to help! What can I do for you?
221 -> API Error: Connection to the API was lost (ECONNRESET). This is usually temporary — try again.
219 -> Pong! 👋 What can I help you with?
221 -> API Error: Connection to the API was lost (ECONNRESET). This is usually temporary — try again.
219 -> Pong! I'm ready to help. What would you like to work on?
221 -> Pong! I'm here and ready to help. What would you like to work on?
219 -> Pong! I'm ready to help. What would you like to work on?
221 -> API Error: Connection to the API was lost (ECONNRESET). This is usually temporary — try again.
219 -> Pong! Ready to help. What would you like to work on?
221 -> Pong! I'm ready to help. What would you like to work on?
219 -> pong 👋 Ready to help with whatever you're working on!
221 -> Pong! I'm ready to help. What would you like to work on?
219 -> Pong! I'm here and ready to help. What would you like to work on?
221 -> Pong! I'm here and ready to help. What can I do for you?
219 -> pong
221 -> Pong. What can I help with?
219 -> Pong! Ready to help. What would you like to work on?
221 -> Pong! I'm ready to help. What would you like to work on? API Error: Connection closed mid-response. The response above may be incomplete.

</details>

---

This isn't context size or the desktop app

Worth stating explicitly, since it narrows things further:

  • My repro is a bare CLI invocation — no desktop app, no MCP servers, a four-character prompt (-p ping). It still fails at ~50% on 221.
  • So "Code uploads the full context each turn" isn't the discriminator. Your own empty-directory test pointed the same way.
  • The desktop app amplifies it rather than causing it. One prompt there is a chain of requests; at ~50% per request a five-step task completes about 3% of the time. That matches your 45-minute observation.

---

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:

$b = "...\LocalCache\Roaming\Claude\claude-code"
Move-Item "$b\2.1.222" "<outside the tree>"
New-Item -ItemType Junction -Path "$b\2.1.222" -Target "<path to 2.1.220>"

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.2212.1.221.broken in place and put the junction beside it. The app loaded the renamed folder anyway:

[info] Using Claude Code binary at: ...\claude-code\2.1.221.broken\claude.exe

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.219 yields a platform binary that reports 2.1.220. Useful to know if you're trying to obtain a specific older build — check what you actually got with --version before relying on it.

---

What the app records

From the session JSONL:

{
  "type": "system", "subtype": "api_error", "level": "error",
  "error": {
    "message": "Connection error.",
    "formatted": "Unable to connect to API (ECONNRESET)",
    "connection": { "code": "ECONNRESET", "isSSLError": false },
    "isNetworkDown": false,
    "rateLimits": null
  },
  "retryInMs": 598, "retryAttempt": 1, "maxRetries": 10,
  "source": "connection_retry",
  "entrypoint": "claude-desktop",
  "version": "2.1.221"
}

"rateLimits": null with no status code — no HTTP response was received at all, so this isn't a 429/529 surfacing as a connection error. isSSLError: false rules 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× curl to api.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.221 release notes mention changes to MCP connection handling in print mode (-p) — servers from --mcp-config not being connected before the first turn — plus MCP connect behaviour and sandbox proxy TLS handling. My repro is -p mode. 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

  • This may be a regression in recovery rather than in causation. If the server is closing streams, what I've measured is that 221 fails to recover where 220 does. Same observable outcome, different root cause; my data can't separate them.
  • 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.220 or 2.1.219 eliminates the failures here rather than mitigating them — worth trying alongside CLAUDE_CODE_MAX_RETRIES=20, given the note that the client doesn't self-recover once the retry loop is exhausted.

MikaGreuzard · 22 days ago

Environment

  • OS: Windows 11 (64-bit), wired Ethernet — Realtek PCIe GbE Family Controller
  • Claude Code: 2.1.226 (native install, ~/.local/bin/claude) — also reproduces in the Claude Desktop app's bundled Code surface
  • Plan: Claude Pro account
  • Network: home fibre (ISP: Bouygues, France). No VPN, no proxy, no antivirus.

Symptom

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)

  • Reachability: curl -I https://api.anthropic.com returns HTTP 404 from the Cloudflare edge on both IPv4 (-4) and IPv6 (-6).
  • MTU: ping 8.8.8.8 -f -l 1472 succeeds (1500 intact); forcing the interface MTU to 1492 had no effect.
  • Realtek NIC: disabled Large Send Offload v2 (IPv4/IPv6), Green Ethernet, Energy-Efficient Ethernet, Gigabit Lite, and NIC power management — no effect.
  • No antivirus; Windows proxy off; no HTTP_PROXY / HTTPS_PROXY / ANTHROPIC_* env vars; ~/.claude/settings.json clean.
  • OpenVPN TAP adapter present but disabled; no active VPN.
  • Config reset: renamed ~/.claude.json and ~/.claude, re-logged in — no effect.
  • MCP: relaunched with --strict-mcp-config --mcp-config (servers reduced) — still resets. The reset is on the main API connection, not on an MCP server.
  • Model: fails on both Sonnet 5 and Opus 5.
  • Router/box reboot — no effect.
  • Cloudflare WARP (routes traffic around the ISP entirely) — still resets, which rules out the ISP/box network path.
  • Version: latest CLI (2.1.226) and the Desktop bundled Code are both affected.

This matches #62045 (Windows + Realtek, network verified healthy, only the Claude Code client resets) and the negative-evidence report in #83994.

Showing cached comments. Read the full discussion on GitHub ↗