[BUG] Regression after 2.1.139: streaming connection resets after first SSE chunk and retries 10 times

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

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Claude Code 2.1.222/2.1.223 on Windows repeatedly loses the streaming
connection immediately after receiving the first SSE chunk when using a custom
Anthropic-compatible API endpoint.

The client retries the same request 10 times. Every attempt receives the first
chunk successfully and then fails with ECONNRESET:

Stream started - received first chunk
Stream connection error (ECONNRESET) — retrying streaming (n/10)

After all streaming retries are exhausted, Claude Code falls back to a
non-streaming request, which succeeds.

The issue occurs in both:

  • Claude Code CLI
  • Claude Code VS Code extension
  • Direct connection to the provider
  • Connection through a local CC Switch proxy

Downgrading only the Claude Code npm package from 2.1.222/2.1.223 to 2.1.139
fixes the issue. Version 2.1.139 streams normally using the same API endpoint,
model, API key, Windows machine, network and settings.

This appears to be a Claude Code streaming transport regression introduced
after version 2.1.139.

What Should Happen?

Claude Code should keep reading the SSE response until the message_stop event,
as version 2.1.139 does.

It should not close or reset the connection after the first SSE chunk, retry
the complete request 10 times, or require the non-streaming fallback.

Error Messages/Logs

[DEBUG] [API:timing] dispatching to firstParty model=claude-opus-4-8[1m]
[DEBUG] [API REQUEST] /v1/messages source=sdk
[DEBUG] Stream started - received first chunk
[DEBUG] [API:timing] first byte after 337ms
[WARN] Stream connection error (ECONNRESET) — retrying streaming (4/10)

[DEBUG] [API REQUEST] /v1/messages source=sdk
[DEBUG] Stream started - received first chunk
[DEBUG] [API:timing] first byte after 364ms
[WARN] Stream connection error (ECONNRESET) — retrying streaming (5/10)

[DEBUG] [API REQUEST] /v1/messages source=sdk
[DEBUG] Stream started - received first chunk
[WARN] Stream connection error (ECONNRESET) — retrying streaming (6/10)

After retry 10/10:

Error streaming, falling back to non-streaming mode:
The socket connection was closed unexpectedly. For more information, pass
`verbose: true` in the second argument to fetch()

The subsequent non-streaming /v1/messages request succeeds.

Steps to Reproduce

  1. Install Claude Code 2.1.223 on Windows using npm:

npm install -g @anthropic-ai/claude-code@2.1.223

  1. Configure an Anthropic-compatible endpoint in ~/.claude/settings.json:

{
"env": {
"ANTHROPIC_API_KEY": "REDACTED",
"ANTHROPIC_BASE_URL": "https://api.deepseek.com/anthropic",
"ANTHROPIC_MODEL": "deepseek-v4-pro",
"ANTHROPIC_DEFAULT_HAIKU_MODEL": "deepseek-v4-pro",
"ANTHROPIC_DEFAULT_OPUS_MODEL": "deepseek-v4-pro",
"ANTHROPIC_DEFAULT_SONNET_MODEL": "deepseek-v4-pro"
}
}

  1. Start Claude Code with debug logging:

claude --debug

  1. Send a simple message such as:

Reply with exactly OK

  1. Observe that Claude Code receives the first streaming chunk and then reports

ECONNRESET. It repeats the request 10 times before falling back to a
non-streaming request.

  1. Downgrade Claude Code without changing any other configuration:

npm install -g @anthropic-ai/claude-code@2.1.139

  1. Run the same request again.
  1. Observe that version 2.1.139 completes the streaming response normally.

Claude Model

Other

Is this a regression?

Yes, this worked in a previous version

Last Working Version

2.1.139

Claude Code Version

2.1.223 (Claude Code)

Platform

Other

Operating System

Windows

Terminal/Shell

PowerShell

Additional Information

A direct curl request to the same endpoint successfully receives a complete
SSE response, including:

  • message_start
  • content_block_start
  • ping
  • content_block_delta
  • content_block_stop
  • message_delta
  • message_stop

Therefore, the endpoint can return a complete valid SSE stream from the same
machine and network.

The issue is also reproducible when bypassing CC Switch and connecting Claude
Code directly to:

https://api.deepseek.com/anthropic

Conversely, Claude Code 2.1.139 works correctly through both the direct endpoint
and the proxy.

The request payload, provider, model, credentials, network and operating system
were unchanged between the failing and working tests. Only the Claude Code
version changed.

This may be related to a change in the Bun/fetch streaming transport,
connection-pool reuse, or SSE response handling introduced between 2.1.139 and
2.1.222.

Related reports with similar ECONNRESET and streaming retry behavior:

View original on GitHub ↗

3 Comments

k-shiga-fn · 23 days ago

Confirming this on Windows 11, and adding measurements that localise the fault inside the client.

Same symptom: first byte arrives, connection is reset ~5 ms later, 10 retries over ~200 s, then the non-streaming fallback succeeds. Affected on desktop-app-bundled 2.1.221 and npm 2.1.222 / 2.1.223. Onset here was 2026-08-05 10:40 JST — 2.1.222 was published 05:37 the same morning.

05:23:24.529 [DEBUG] [API:timing] first byte after 1511ms
05:23:24.534 [WARN]  Stream connection error (ECONNRESET) - retrying streaming (1/10)
...
05:26:41.105 [ERROR] Error streaming, falling back to non-streaming mode

1. Retries never succeed — only the fallback does

Counted over one session log: 137 retry lines, 0 successful retries. Recovery came exclusively from the non-streaming fallback, so the ~200 s spent retrying is pure loss. This matches the stale-connection-pool hypothesis in #23081.

2. The reset originates inside the machine

I interposed a local HTTP CONNECT proxy on 127.0.0.1:8321 (plain TLS passthrough — no MITM, no certificate) and pointed the client at it with HTTPS_PROXY. That splits the TCP path into a loopback leg and an upstream leg so they can be observed separately. Over ~103 tunnels to api.anthropic.com:

13  client    api.anthropic.com  ECONNRESET   <- client sends RST on the 127.0.0.1 socket
 7  upstream  api.anthropic.com  EPIPE        <- consequence: peer already torn down

The resets arrive on the loopback leg. No router, NAT, Wi-Fi or firewall is on that path, which rules out the NAT-idle-timeout mechanism proposed in #67091 for this failure mode.

(Note: CLAUDE_CODE_HTTPS_PROXY is ignored — 0 connections through the proxy with it set. Only the standard HTTPS_PROXY is honoured. A sign-out/sign-in was needed for the variable to propagate; restarting the app was not enough.)

3. Connections accumulate and are never reaped

Get-NetTCPConnection during ordinary use of a single session plus scheduled tasks:

Loopback  (Claude Code <-> proxy)        140 Established,  0 CloseWait,  4 TimeWait
Upstream  (proxy <-> api.anthropic.com)  140 Established
    of which 129 to 160.79.104.10

10:31    86 concurrent / 177 total
10:53   141 concurrent / 374 total

0 CLOSE_WAIT on the loopback side shows the proxy is not leaking — the client genuinely holds all 140 open, and the count climbs monotonically. For HTTP/2 a handful of multiplexed connections should suffice. This looks consistent with the "connection-pool reuse" suspicion in the original report.

4. The server is fine throughout

A direct POST /v1/messages from the same machine, at the same moment, with Claude Code's own headers returns HTTP 200 in 1.5 s.

Trap for anyone reproducing this: a bare curl to /v1/messages with a subscription OAuth token returns 429 {"type":"rate_limit_error","message":"Error"} unless you also send user-agent: claude-cli/..., x-app: cli, anthropic-beta: oauth-2025-04-20,claude-code-20250219 and a Claude Code system prompt. That 429 is not a real quota problem — it cost me half a day.

Partial workaround

CLAUDE_CODE_MAX_RETRIES=4 — since retries never succeed, a smaller budget reaches the working fallback sooner. 199–210 s → 21–45 s for a trivial prompt. Mitigation only; the connection accumulation is unaffected. =1 is faster still (15–20 s) but surfaces "connection problem" errors more often, as a separate retrying streaming (1/2) path gives up immediately.

Impact and what was ruled out

This machine runs ~30 scheduled Claude Code routines in production; they were unusable for two working days and the work had to be done by hand. In case it saves anyone else the time, all of the following were tested and excluded: mobile tethering, Wi-Fi drops, endpoint security, proxy/certificates, request size (a 320 KB body uploads in 1.8 s), client startup (claude --version 2.8 s), empty settings, fully disabled MCP, account limits (Max 5x at 13 % session / 34 % weekly), and host memory.

dezmondz-ycb · 23 days ago

Bisected to the exact release: 2.1.221.
Fresh npm installs on the same machine (Windows 11, standard api.anthropic.com endpoint, Max subscription), tested minutes apart today:

  • 2.1.139: works
  • 2.1.220 (24 Jul): WORKS — complete streamed responses, zero ECONNRESET
  • 2.1.221 (3 Aug): FAILS — first prompt errors straight into the retry loop
  • 2.1.222 / 2.1.223 / 2.1.224 (published 7 Aug): fail identically

So the regression entered in 2.1.221 — consistent with @k-shiga-fn's observation that the app-bundled 2.1.221 is affected. Same config/credentials across all tests; only the version changed. Currently pinned to 2.1.220, fully stable. Onset for me was 5 Aug, matching the desktop app picking up the broken line.

k-shiga-fn · 18 days ago

Still reproducing on 2.1.227, and the desktop app now force-installs it over a pinned good build.

Nothing in 2.1.223–2.1.227 addresses this. Those changelogs cover feature-flag evaluation, claude-code-action, /tui, the slash-command menu and event-loop stalls; 2.1.226 is just "Bug fixes and reliability improvements". Confirmed empirically below.

Controlled A/B this morning (2026-08-12 JST)

The desktop app auto-updated (1.26832.0 → 1.28929.0.0), pulled 2.1.227 into a new directory, and silently bypassed the 2.1.220 binary I had pinned. Same machine, same network, same account, same hour:

| Time | Build in use | Result |
|---|---|---|
| 09:35:23 | 2.1.227 | ECONNRESET at 09:37:30 (~2 min in) |
| 09:40:28 | swapped 2.1.220 back in | — |
| 09:48:26 → now | 2.1.220 | zero ECONNRESET |

2.1.220 had also run clean for the preceding three days on this machine. The only variable that changed was the build.

The stable channel has moved onto the bad build

  • 2026-08-09: .../claude-code-releases/stable2.1.220, latest2.1.226
  • 2026-08-12: stable2.1.221, latest2.1.228

If the bisect in this thread is correct (@dezmondz-ycb's, plus my own result that 2.1.220 is clean), stable now points at the first affected build. Worth someone at Anthropic checking before more users are moved onto it.

Desktop-app users: npm pinning does not help you

The desktop app ignores the release channels and resolves a version hardcoded per app build:

[CCD] Initialized with version 2.1.227
[CCD] Downloading from https://downloads.claude.ai/claude-code-releases/2.1.227/win32-x64/claude.exe.zst
Using Claude Code binary at: %APPDATA%\Claude\claude-code\2.1.227\claude.exe

There is no setting to opt into stable. The only workaround I have found is replacing the binary in that directory with 2.1.220:

  1. Download https://downloads.claude.ai/claude-code-releases/2.1.220/win32-x64/claude.exe.zst
  2. Decompress it. No zstd binary needed — Node 24 can do it:

require('zlib').zstdDecompressSync(buf, {maxOutputLength: 1<<30})
(the size cap matters; the output is ~253 MB and the default limit rejects it)

  1. Verify before you run it. SHA-256 against platforms.win32-x64.checksum in .../claude-code-releases/2.1.220/manifest.json, and confirm Authenticode is Valid with CN="Anthropic, PBC". Please don't skip this step or take a binary from anywhere else.
  2. Rename the existing claude.exe (a running exe can't be overwritten, but it can be renamed), drop 2.1.220 in as claude.exe, restart the app.

Two caveats worth knowing:

  • The app does not re-verify the binary's hash at launch, which is why the swap survives restarts. Convenient for this workaround, but it is an integrity gap that probably deserves its own look.
  • An app update creates a new version directory and silently reverts you. Mine did exactly that this morning and I was back in the retry loop two minutes later. Keep the verified 2.1.220 copy somewhere outside the app directory — you will need it again.

Ask

This issue has been open six days with no maintainer response, and I have had no reply on a paid-plan (Max) support ticket opened the same day. Could someone from Anthropic confirm:

  1. whether 2.1.221 is the build that introduced this,
  2. whether stable pointing at 2.1.221 is intentional, and
  3. which build is currently safe to run?

Happy to supply debug logs, packet captures, and the connection-count measurements from my earlier comment.

Showing cached comments. Read the full discussion on GitHub ↗