[BUG] Deterministic ECONNRESET / "Connection closed mid-response" on requests above ~100 KB (mainland China + full-tunnel VPN)
- [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
Preflight Checklist
I have searched existing issues: this matches the fingerprint of #56140 and #51164 (both size-correlated ECONNRESET). I'm filing this because it adds (a) a deterministic, measured payload-size reproducer and (b) an environment class (mainland China behind a full-tunnel VPN) not covered by the existing reports.
This is a single bug report.
Reproduced on the latest version (2.1.223) at the time of testing.
What's Wrong?
Claude Code sessions fail with Unable to connect to API (ECONNRESET) · Retrying in Ns · attempt N/10, or with API Error: Connection closed mid-response. The response above may be incomplete.
The failure correlates cleanly with request body size, not with connectivity:
Tiny claude -p requests (a few KB) succeed.
Real interactive sessions (project context + system prompt + history, i.e. anything ≥ ~100 KB per request) fail through all 10 retries.
The problem comes in waves: hours where every large request dies, then windows where everything passes in ~1 s. Small requests pass in both windows.
Both surfaces are affected identically: the terminal CLI and the Desktop app's Code tab (Desktop-managed runtime). Claude.ai Chat in the browser and Cowork are unaffected (small request bodies).
Environment
Claude Code: 2.1.223 (native installer), later also 2.1.220 (stable channel) — see "Version datapoints" below
OS: Windows 11 x64, PowerShell
Auth: claude.ai OAuth (Max plan)
Model: Opus 5 (1M context) sessions; also reproduced with default model after removing the model pin
Location: mainland China, behind the GFW
VPN: Astrill, full tunnel (verified: route 128.0.0.0/1 via tunnel interface, metric 1 — no split routing). Reproduced under both WireGuard and StealthVPN, exit nodes in Japan
Tunnel interface MTU: 1280
Line through tunnel: ~7.4 Mbps down / ~7.9 Mbps up; loaded latency 573 ms down / 1127 ms up (significant bufferbloat on the uplink)
Deterministic reproducer
Run during a failure window (PowerShell):
powershell
foreach ($n in 500, 5000, 20000) {
$s = "filler words " * $n
$kb = [math]::Round($s.Length/1KB)
Write-Host "--- payload ~$kb KB ---"
$t = Measure-Command { $s | claude -p "Reply only: OK" | Out-Host }
"{0} KB -> {1:n1} s" -f $kb, $t.TotalSeconds
}
Observed result during a failure window:
--- payload ~11 KB ---
OK
11 KB -> 7.1 s
--- payload ~107 KB ---
OK
API Error: Connection closed mid-response. The response above may be incomplete.
107 KB -> 7.4 s
--- payload ~430 KB ---
OK
API Error: Connection closed mid-response. The response above may be incomplete.
430 KB -> 24.1 s
The threshold is sharp and repeatable within a failure window: ~11 KB always passes, ~107 KB and above always fails. During a good window the exact same 107 KB payload completes in ~1 s.
Ruled out (all verified during failure windows unless noted)
Proxy configuration: no HTTP_PROXY/HTTPS_PROXY/NO_PROXY/ANTHROPIC_BASE_URL at process, user, or machine scope; WinINET and WinHTTP proxies both direct/empty.
DNS: api.anthropic.com resolves correctly (160.79.104.10); lookups in 0.01–0.7 s.
Basic connectivity: Test-NetConnection api.anthropic.com -Port 443 succeeds; curl.exe https://api.anthropic.com/v1/models returns HTTP 401 in 0.5–2.6 s consistently (10/10 attempts) including while CLI sessions were failing.
Large upload capability of the tunnel itself: 5 MB POST to speed.cloudflare.com/__up → HTTP 200, all bytes, 8.4 s. 200 KB POST via curl to api.anthropic.com/v1/messages → HTTP 401 (auth-rejected, but fully transmitted) in 2.7 s during a good window.
MCP servers: reproduced with --strict-mcp-config --mcp-config '{"mcpServers":{}}' (note: the claude.ai Google Drive connector times out from China — MCP error -32001 on drivemcp.googleapis.com — which slows session startup, but it is not the cause of the resets).
Model pin: originally had "model": "claude-fable-5[1m]" in settings.json; removed, still reproduced.
Split routing: full tunnel confirmed via Find-NetRoute; browser and CLI traffic take the same path.
Project-level config: .claude/settings.local.json contains only permissions.allow entries.
Version datapoints (reported for completeness — causality NOT established)
Failures were first noticed around the auto-update to 2.1.223 (2026-08-06) and around the Aug 4–5 status-page incidents.
After claude install stable (2.1.220), interactive sessions worked.
However, 2.1.223 also passed the 107 KB reproducer in ~1 s during a good window roughly one hour before the downgrade, on an unchanged system. So the wave pattern confounds any version attribution. #56140 documents the same fingerprint on 2.1.114/2.1.126, which predates 2.1.223 by months.
Hypothesis / relation to existing reports
Fingerprint matches #56140 (ECONNRESET errno: 0, persists through all 10 retries, curl healthy at the same time, concentrated in long-context 1M sessions, size-correlated) and #51164 (mid-stream ECONNRESET on large-context sessions).
Consistent with the upload-burst mechanism analyzed in the community (gist: https://gist.github.com/arutkayb/f56e7a4e1d8b50a6064645c327749fbc): every request uploads the full conversation context as the POST body; the TCP stack bursts it into a constrained uplink buffer; on overflow the flow stalls and the connection is reset. On my link (≈8 Mbps up, 1127 ms loaded latency) this would also explain the wave pattern — failures appear when concurrent upstream traffic saturates the uplink, and disappear when the line is idle — and why small requests always pass.
The retry behavior makes recovery less likely on constrained uplinks: each retry immediately re-uploads the full body, re-saturating the line it just choked on.
Suggested improvements
Pace or cap the send rate of large request bodies (the gist above shows pacing eliminates the resets on an affected line).
Surface better diagnostics on reset: bytes transmitted before the reset would make this class of failure (uplink overflow vs. server-side RST_STREAM) immediately distinguishable.
Consider making retries after ECONNRESET use a reduced-rate first attempt.
Happy to provide additional logs or run instrumented builds — the failure windows recur, and the reproducer above turns them into a 30-second test.
What Should Happen?
Large request bodies should transmit reliably (e.g. paced/streamed uploads), or fail fast with actionable diagnostics (bytes sent before reset), instead of dying with a generic ECONNRESET through all 10 retries.
Error Messages/Logs
API Error: Connection closed mid-response. The response above may be incomplete.
Unable to connect to API (ECONNRESET) · Retrying in 7s · attempt 5/10
Richiesta non riuscita · nuovo tentativo (1/10) · 25s (Desktop app, Italian locale)
Steps to Reproduce
- Environment: Windows 11, Claude Code 2.1.223 (native installer), signed in via claude.ai OAuth (Max plan), mainland China behind a full-tunnel VPN (Astrill, WireGuard or StealthVPN, Japan exit) on a constrained uplink (~8 Mbps up, high bufferbloat). Wait for a "failure window" (they recur for hours at a time; during them, interactive sessions show ECONNRESET retry loops).
- Verify the path itself is healthy (all of these succeed even during failure windows):
curl.exe -sS -o NUL -w "HTTP %{http_code} in %{time_total}s" --max-time 20 https://api.anthropic.com/v1/models
→ HTTP 401 in 0.5–2.6 s, 10/10 attempts.
- Run the size-scaling reproducer in PowerShell:
foreach ($n in 500, 5000, 20000) {
$s = "filler words " * $n
$kb = [math]::Round($s.Length/1KB)
Write-Host "--- payload ~$kb KB ---"
$t = Measure-Command { $s | claude -p "Reply only: OK" | Out-Host }
"{0} KB -> {1:n1} s" -f $kb, $t.TotalSeconds
}
- Observe: ~11 KB passes; ~107 KB and ~430 KB return "API Error: Connection closed mid-response. The response above may be incomplete." Same behavior with MCP disabled (
--strict-mcp-config --mcp-config '{"mcpServers":{}}'). During good windows the identical 107 KB payload completes in ~1 s.
Claude Model
Opus
Is this a regression?
Yes, this worked in a previous version
Last Working Version
Not sure
Claude Code Version
2.1.220 (stable) currently works, but causality is not established — see "Version datapoints" in the description: 2.1.223 also passed the reproducer during a good window, and #56140 shows the same fingerprint on 2.1.114/2.1.126.
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
PowerShell
Additional Information
Related reports: #56140 (closed as duplicate — same fingerprint: ECONNRESET errno 0, size/context-correlated, curl healthy, on versions 2.1.114/2.1.126) and #51164 (mid-stream ECONNRESET on large-context sessions).
Community analysis of the upload-burst mechanism, including a pacing-based fix that eliminates the resets on an affected line: https://gist.github.com/arutkayb/f56e7a4e1d8b50a6064645c327749fbc
Possibly confounding: the status.claude.com incidents of Aug 4–5, 2026 (elevated errors on multiple models) overlapped my first failure window.
Both the terminal CLI and the Desktop app's Code tab (Desktop-managed runtime, 2.1.223) fail identically; claude.ai Chat in the browser and Cowork on the same machine/network are unaffected (small request bodies). Screenshots of the retry loops available on request.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗