VS Code extension: session hangs indefinitely on stalled SSE stream (no idle-timeout/reconnect)

Status Open
Reported on v2.1.278
Maintainer reply None cached
Activity 3 comments · opened Sep 20, 2026

Summary

Claude Code sessions in the VS Code extension intermittently hang indefinitely mid-response, with no error, no timeout, and no recovery. The process is left idle (blocked in kevent64/kqueue wait) waiting on a streaming HTTPS connection that has gone silent. There is no client-side idle-read timeout or reconnect logic, so the session — and the VS Code panel bound to it — freezes permanently until manually killed.

Environment

  • Claude Code VS Code extension: anthropic.claude-code 2.1.278
  • Native binary: resources/native-binary/claude (Bun-based runtime — confirmed via thread names Bun Pool 0/1, HTTP Client, mi-scavenger in stack sample)
  • OS: macOS 26.5.2 (25F84), Apple Silicon (ARM64)
  • Network: home Wi-Fi + wired, no corporate proxy, no VPN interception (confirmed no HTTPS_PROXY/NODE_EXTRA_CA_CERTS env vars, no MDM/TLS-inspection software running)

Symptom

  1. Start a new Claude Code session/turn in the VS Code panel.
  2. The turn begins normally: [engine] turn 1 start → Stream started - received first chunk logged within ~500ms.
  3. After the first chunk, all further progress silently stops. No more log lines (no tool calls, no additional stream chunks, no completion, no error) for minutes.
  4. The panel shows the session as state: running indefinitely. VS Code itself sometimes becomes fully unresponsive and requires a full quit/relaunch (not just "Reload Window") to recover — 3 full app relaunches observed in a 12-minute span in one incident.
  5. This has now been reproduced twice with the identical prompt/session in back-to-back attempts.

Root cause evidence (captured live with sample)

Ran sample <pid> 3 on the stalled native-binary process mid-hang. Key findings:

  • Main thread (DispatchQueue_1: com.apple.main-thread) and a dedicated "HTTP Client" thread are both blocked in kevent64 (kqueue event wait) with ~0% CPU — i.e., genuinely idle, not busy-looping, not blocked on file I/O (no APFS/read syscalls anywhere in the stack — ruled out iCloud/file-materialization as a cause).
  • lsof/netstat on the stalled process at the time of the hang showed 4 concurrent established HTTPS connections to Anthropic's API edge (2607:6bc0::10:443), all in TCP ESTABLISHED state with empty Recv-Q/Send-Q — no error at the TCP layer, no retransmission backlog, nothing that would surface as a socket error to the client.
  • All other network activity on the machine (Dropbox, Google services, Mattermost, etc.) was healthy and actively transferring data at the same moment — ruling out a general connectivity/Wi-Fi outage. No interface flap/roam events in the unified log for the relevant window.
  • Ruled out: disk space / iCloud Drive file materialization stalls (no file I/O in the stack), corporate TLS interception (no proxy configured, no MDM agents running), zombie/uninterruptible processes (none found), orphaned process accumulation across restarts (none found).

Conclusion

One of the pooled HTTPS connections used for the active SSE stream goes silent — most likely due to a middlebox (e.g., home router NAT table aging out an idle "established" mapping without sending RST/FIN) dropping the path without either endpoint being notified. Since the client has no idle-read timeout and no reconnect/retry logic for a stalled stream, it waits in kevent64 forever. Nothing detects or recovers from this condition; the only recovery today is manually killing the process (or, if VS Code itself has wedged, force-quitting the whole app).

Suggested fix

  • Add an idle-read timeout on the streaming HTTP response (e.g., if no chunk/keepalive received within N seconds, treat the stream as dead).
  • On timeout, abort the stalled connection and automatically retry/reconnect the turn (or surface a clear "connection stalled, retrying…" state to the user) rather than hanging indefinitely.
  • Consider enabling TCP keepalive with a short interval on the underlying sockets so dead connections are detected at the OS level sooner.

Attachments

Raw sample output available on request (stack trace of stalled main + HTTP Client threads in kevent64).

View original on GitHub ↗

3 Comments

dvgf · 24 days ago

Second independent reproduction

Reproduced again in a fresh VS Code session shortly after filing this issue. Same signature, with one new detail:

  • This time the stall happened before the first stream chunk ever arrived (previous reproduction got at least one chunk before going silent) — so the hang isn't limited to "stream starts then dies mid-flight," it can also happen on the very first response.
  • sample <pid> 3 again showed the main thread and the dedicated "HTTP Client" thread both parked in kevent64 (kqueue wait), ~0% CPU, no progress.
  • Confirmed DNS resolves correctly (api.anthropic.com → 160.79.104.10), and the stuck process held a genuine ESTABLISHED TCP connection to that exact IP on 443, alongside 3 more established connections to 2607:6bc0::10. No connection errors, no RST, nothing — it just never got/processed a response, and the client has no timeout to detect or recover from that.
  • Two separate resumed sessions in the same VS Code window stalled simultaneously on the same pattern.
  • Killing the stuck native-binary processes and starting fresh is still the only recovery; a VS Code "Reload Window" was sufficient this time (didn't require a full app relaunch).

This reinforces that the fix needs to cover both "stream stalls after starting" and "response never starts at all" — i.e., a timeout should apply from request-sent, not just from first-byte-received.

dvgf · 24 days ago

Third reproduction + key differential test

Third stall in ~10 minutes, 3-for-3 on fresh sessions (new PID each time, no carried-over connection pool between attempts). Same signature: main + HTTP Client threads parked in kevent64, 0% CPU, no progress after the initial chunk.

Differential test: ran a raw, unauthenticated curl to the same host immediately after clearing the stuck process:

curl -sS -o /dev/null -w "HTTP %{http_code} | connect:%{time_connect}s tls:%{time_appconnect}s ttfb:%{time_starttransfer}s total:%{time_total}s\n" https://api.anthropic.com/v1/messages
→ HTTP 405 | connect:0.012s tls:0.025s ttfb:0.040s total:0.040s

Instant, clean TLS handshake and response — no packet loss, no path/ISP issue, no general reachability problem at the time of the hang. This is a useful negative result: it means the failure is not a generic "network is flaky right now" condition (which would also slow down/break the plain curl request). It's specific to the Claude Code client's actual authenticated streaming request — each fresh process, brand new connection, still stalls, while a simple unrelated HTTPS request to the same host succeeds trivially.

This shifts my read of the likely cause somewhat: rather than (or possibly in addition to) a NAT idle-timeout theory, this looks like it could be something in how the client negotiates/handles its specific request (e.g. HTTP/2 stream that gets accepted at the connection level but never receives a response on that particular stream) — something that would require server-side visibility (load balancer / edge logs for the specific request IDs) to fully pin down. Happy to provide the x-client-request-id values from the affected turns if useful (visible in the extension's debug log as [API REQUEST] ... x-client-request-id=...).

Given the 3-for-3 rate in a short window, this may currently be an elevated-frequency period rather than the rare occasional stall it seemed to be initially.

dvgf · 24 days ago

Likely version regression: 2.1.258 (works) vs 2.1.278 (hangs)

Fourth stall in ~20 minutes via the VS Code extension (which bundles native-binary claude 2.1.278). Meanwhile, a completely separate Claude Code CLI session running directly in a terminal on the same machine, same network, same Mac — using CLI version 2.1.258 (installed via /Users/georgefoulard/.local/bin/claude, not the VS Code-bundled binary) — has been running continuously for 43+ minutes with zero stalls, multiple turns, tool calls, everything working normally.

Same machine, same network path (already confirmed healthy via raw curl to api.anthropic.com), same time window — the only material difference identified so far is the CLI version (2.1.258 vs 2.1.278) and the extra flags the VS Code extension passes (--permission-prompt-tool stdio --include-partial-messages --enable-auth-status --no-chrome --replay-user-messages, etc., none of which the plain terminal invocation uses).

This strongly suggests either:

  1. A regression introduced somewhere between 2.1.258 and 2.1.278 in the HTTP/streaming client, or
  2. A behavior specific to one of the VS Code-extension-only CLI flags (e.g. --include-partial-messages or --replay-user-messages) that changes how the streaming connection is handled/kept alive.

Given the sharp contrast (0/4 vs the terminal's 0-stalls-in-43-minutes), pinning down the changelog between these two versions for the HTTP client / streaming code path seems like the fastest way to find the actual root cause.