[Windows] Persistent ECONNRESET on streaming API connections due to missing SO_KEEPALIVE (~346s pattern)

Open 💬 0 comments Opened Jun 10, 2026 by ega244127-web

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 on Windows repeatedly loses its streaming API connection with ECONNRESET after approximately 340–360 seconds of inactivity within a session. This has occurred consistently since at least May 2026 across multiple Claude Code versions (v1.6608.2.0 through v2.1.165), and persists even after configuring Windows TCP keepalive at the OS level — suggesting the application does not set SO_KEEPALIVE on its API sockets.

From %APPDATA%\Claude\logs\main.log:

[warn] [CCD CycleHealth] <session_id> api_error (success): API Error: Unable to connect to API (ECONNRESET)
[info] [CCD CycleHealth] unhealthy cycle for <session_id> (350s, hadFirstResponse=true, reason=api_error)
[error] Session <session_id> query error: Claude Code process exited with code 1073807364

From telemetry (1p_failed_events files), tengu_api_retry events:

{
  "attempt": 6,
  "error": "Connection error.",
  "provider": "firstParty",
  "attempt_duration_ms": 15019,
  "delayMs": 17906
}

All 6 retries are exhausted before the session terminates.

Statistical pattern (extracted from rotated log main1.log, 30+ incidents since 2026-05-10):

  • hadFirstResponse=true in every single case — connection and first response always succeed; reset happens mid-session
  • Cycle duration at error clusters tightly at 337–355 seconds — far too consistent to be random; matches the NAT idle TCP timeout of the home router
  • Longer sessions involving active tool calls do not hit the timeout (the data flow resets the NAT idle timer)

OS-level TCP keepalive is already configured:

HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
  KeepAliveTime     = 0xEA60  (60,000 ms = 60 s)
  KeepAliveInterval = 0x2710  (10,000 ms = 10 s)

Despite this, the ~346 s ECONNRESET pattern continues unchanged. On Windows, KeepAliveTime only applies to sockets that have SO_KEEPALIVE explicitly enabled by the application (socket.setKeepAlive(true) in Node.js). The fact that the 60 s OS setting has no effect is strong evidence that the API connection socket does not have SO_KEEPALIVE set.

What Should Happen?

The streaming API connection should survive periods of inactivity (e.g., while Claude is processing a long task with no intermediate output). TCP keepalive probes should be sent at a sub-NAT-timeout interval to keep the connection alive through home routers.

Suggested fix: Enable TCP keepalive on the socket used to connect to api.anthropic.com:

// When creating the HTTPS socket / agent for the Anthropic API
agent.on('socket', (socket) => {
  socket.setKeepAlive(true, 30_000); // start probes after 30 s idle
});

A 30-second initial delay would ensure probes are sent well before typical consumer router NAT timeouts (commonly 300–360 s).

Error Messages/Logs

# From %APPDATA%\Claude\logs\main.log
[warn] [CCD CycleHealth] local_b81ef33e-... api_error (success): API Error: Unable to connect to API (ECONNRESET)
[info] [CCD CycleHealth] unhealthy cycle for local_b81ef33e-... (350s, hadFirstResponse=true, reason=api_error)
[error] Session local_b81ef33e-... query error: Claude Code process exited with code 1073807364 { stack: 'Error: Claude Code process exited with code 1073807364\n    at _er.getProcessExitError ...' }

# From telemetry 1p_failed_events (tengu_api_retry, base64-decoded additional_metadata)
{"subscription_type":"pro","attempt":6,"delayMs":17906.33,"error":"Connection error.","provider":"firstParty","attempt_duration_ms":15019}
{"subscription_type":"pro","attempt":6,"delayMs":16020.17,"error":"Connection error.","provider":"firstParty","attempt_duration_ms":18970}

# Unhealthy cycle durations sampled from main1.log (30+ occurrences since 2026-05-10)
# hadFirstResponse=true in all cases
346s, 346s, 344s, 349s, 350s, 352s, 353s, 347s, 344s, 346s, 347s, 350s, 337s, 343s, 355s, 344s, 346s, 350s, 352s, 341s ...

Steps to Reproduce

  1. Start a Claude Code session on Windows (Claude Desktop app)
  2. Begin a task that involves long processing time — e.g., asking Claude to analyze a large codebase or run multiple sequential tool calls
  3. Wait without interacting (let Claude "think" or process without user messages)
  4. After approximately 340–360 seconds since the last data was received on the API stream, the session terminates with ECONNRESET
  5. Claude Code retries 6 times (each attempt ~15–19 s) then session dies

Note: The timeout is triggered by inactivity in the TCP stream, not by any user-facing timeout. Sessions with frequent tool calls (continuous data flow) can run for hours without hitting this issue. The ~346 s threshold matches the NAT idle TCP timeout of common consumer routers (IO DATA WN-PL1167EX03 in this case, not user-configurable).

Claude Model

None

Is this a regression?

No, this never worked

Last Working Version

_No response_

Claude Code Version

2.1.165 (claude-sonnet-4-6)

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

Non-interactive/CI environment

Additional Information

  • Entrypoint: claude-desktop (Claude Desktop app for Windows), not CLI
  • Auth method: OAuth (is_claude_ai_auth: true, not API key)
  • Node.js version: v24.3.0
  • Router: IO DATA WN-PL1167EX03 — NAT TCP session timeout is not user-configurable on this consumer device
  • MCP tool count: 96 tools loaded (noted in telemetry mcpToolCount: 96) — long thinking periods increase exposure to the timeout
  • netsh int tcp show global does not expose a keepalivetime parameter — OS keepalive must be set via registry and only takes effect if SO_KEEPALIVE is set per-socket by the application
  • The issue also appears in the Anthropic SDK level — the fix should be applied wherever the streaming HTTPS connection to api.anthropic.com is established

View original on GitHub ↗