VS Code/Cursor extension: session hangs forever after auto-mode classifier_request_finished (no timeout, webview channel errors silenced)

Status Open
Reported on v2.1.220
Maintainer reply None cached
Activity 3 comments · opened Jul 26, 2026

Summary

In the VS Code / Cursor extension, sessions freeze mid-run several times per session (4-6x). The hang happens in the auto-mode permission path: the permission classifier request completes successfully, but the decision never reaches dispatch — no tool_dispatch_start, no permission prompt, no error, and no timeout, so the session waits forever. The UI shows nothing; the only recovery is closing and reopening the chat (which rebuilds the webview channel) and sending a new message. Because the stall usually outlives the prompt-cache TTL, each recovery re-sends the full context uncached (~14% of a session's usage burned per stall).

Environment

  • Extension: Claude Code for VS Code, cc_version=2.1.220.26d, cc_entrypoint=claude-vscode
  • IDE: Cursor on macOS (Darwin 25.5.0)
  • Permission mode: auto (Bash commands routed through the claude-sonnet-5[1m] classifier, stage=xml_s1)
  • Plan: paid subscription

Evidence from Claude VSCode.log

Healthy flow (2026-07-26 17:08:29 UTC) — classifier finishes, decision lands, tool dispatches:

17:08:25.993 [INFO] [Stall] classifier_request_started reqId=37a6e8cd-... tool=Bash model=claude-sonnet-5[1m] stage=xml_s1
17:08:29.564 [INFO] [Stall] classifier_request_finished reqId=37a6e8cd-... outcome=ok durationMs=3571
17:08:29.581 [INFO] Slow permission decision: 3645ms for Bash (mode=auto, behavior=allow)
17:08:29.591 [INFO] [Stall] tool_dispatch_start tool=Bash toolUseId=toolu_01BQWDA1PsLZBiXdYSL2YRtr permissionDecisionMs=3645

Hang, 3 minutes later (2026-07-26 17:11 UTC) — same session, classifier finishes, then nothing, forever:

17:11:25.885 [INFO] [Stall] classifier_request_started reqId=1f0bae18-4ea6-47d5-a9f5-d2f0980acf8c tool=Bash model=claude-sonnet-5[1m] stage=xml_s1
17:11:25.955 [DEBUG] [API REQUEST] /v1/messages x-client-request-id=23678dae-fd3f-4140-beb1-28d7558d1888 source=side_query
17:11:28.436 [INFO] [Stall] classifier_request_finished reqId=1f0bae18-4ea6-47d5-a9f5-d2f0980acf8c tool=Bash stage=xml_s1 outcome=ok durationMs=2551
   <-- nothing after this: no permission decision, no tool_dispatch_start, no error, no timeout -->
17:14:58.521 [DEBUG] Invalidating session environment cache   <-- user closed/reopened the chat to recover

The command being classified was npx vitest ... (an allow-suggestion for it was logged at 17:11:25.829).

Likely related — every session start logs a webview channel error and then goes silent about further drops, which would explain why the hangs leave no error trace:

[WARN] claude-vscode notification channel error: Received a response for an unknown message ID: {"jsonrpc":"2.0","result":{},"id":0}; further channel errors are not logged this session

A second symptom of the same channel flakiness observed the same evening (17:28:16 UTC): the webview flipped the session to state:"idle" while a subagent (source=agent:builtin:general-purpose) was still actively streaming API requests.

Separate but related: silent give-up on 429

Two other freezes were a different failure: on an account rate limit the extension logs API error (attempt 1/11): 429 rate_limit_error but gives up immediately after attempt 1 (API rate_limit after retries) and flips the session to idle with no visible error. Request IDs for server-side lookup:

  • req_011CdPNNLX3yrcUAWzXCkjYN (2026-07-25 19:59 UTC+2)
  • req_011CdQt9Dup3M2oLnovPihZ1 (2026-07-26 15:10 UTC)
  • x-client-request-id 4be74d05-690b-46c0-b5e1-d5a84c4b05bf

Expected behavior

  1. A timeout + retry (or a surfaced error) on the permission-decision path so a dropped channel message cannot hang the session forever.
  2. Channel errors should keep being logged (or re-establish the channel) instead of "further channel errors are not logged this session".
  3. A 429 with retry budget "1/11" should actually retry with backoff, or clearly tell the user why it stopped.

Impact

4-6 hard freezes per working session; each recovery requires closing/reopening the chat and re-sending context uncached, burning a significant share of the session's usage quota.

View original on GitHub ↗

3 Comments

jpmaligne · 2 months ago

Hitting the same "Secondary Issue: Silent Rate Limit Failures" pattern described above, with one additional data point that might help narrow down the root cause: the classifier's own system prompt appears to be the thing burning the rate-limit budget, not the main loop.

Environment

  • Claude Code (VS Code extension), reproduced on both v2.1.152 and v2.1.227 (upgraded mid-investigation, issue persisted identically — not fixed by updating)
  • Linux
  • Permission mode: auto
  • Subscription: Claude Max, at the time of the errors: 41% of 5-hour session limit, 8% of weekly limit used — nowhere near the account's usage cap, which rules out a simple "you're out of quota" explanation.

Evidence: classifier prompt size vs. main request

Claude Code dumps the failing classifier request to /tmp/claude-*/auto-mode-classifier-errors/<sessionId>.txt on error. For a single trivial action ({"Bash":"cd ~/workspace/<project> && ls -la"}), the dump showed:

model: claude-sonnet-5
mainLoopTokens: 14480
classifierChars: 112569
classifierTokensEst: 28142
delta (classifierEst - mainLoop): 13662

The classifier's own request (~28k tokens, system prompt alone is ~112k chars — a "security monitor for autonomous AI coding agents" prompt) is almost twice the size of the main-loop request it's evaluating. In an auto-mode session with many quick sequential tool calls (in my case amplified by a PreToolUse hook that intercepts every Bash invocation individually), this multiplies token throughput fast enough to trip a short-term rate limit even though overall plan usage is low.

Logs (matches the pattern already reported above)

[WARN] [Stall] classifier_request_finished reqId=... tool=Bash stage=xml_s1 outcome=error durationMs=8000-10000 errorKind=Error:429 {"type":"error","error":{"type":"rate_limit_error","message":"Error"}}
[WARN] Auto mode classifier (XML) error: 429 {...}
[DEBUG] Auto mode classifier: Sonnet 5 probe demotion errorKind=http_429

Sample request_ids for backend correlation (repeated ~every 8-30s over multiple 5-10 minute windows, both before and after the version upgrade):

  • req_011CdvjCxJPVuxcSTfyj5R21 (2026-08-11T09:31:28.414Z, v2.1.227)
  • req_011CdvjCAu8udXCvDzXoFLFK (2026-08-11T09:31:17.770Z, v2.1.227)
  • req_011CdvhSEEy1girrtvGf5LHX (2026-08-11T09:08:14.812Z, v2.1.152)
  • req_011CdvhRySE8JvWajjmEuYws (2026-08-11T09:08:11.485Z, v2.1.152)
  • Same pattern also seen on 2026-08-07 (~14:11 UTC), 6 occurrences in that window alone — this is recurring, not a one-off.

Checked status.claude.com at the time: no ongoing incident reported.

Suggested fix direction

Given the classifier prompt is bigger than the request it's classifying, trimming what gets sent to the classifier (e.g. not re-sending full transcript/tool schemas on every single tool call, or caching the static parts) seems like it would both reduce latency (the 8-10s stalls) and make auto mode much less likely to trip short-term rate limits during normal fast-paced sessions — independent of fixing the retry/timeout behavior already requested above.

Happy to share the full dumped classifier-error file (redacted) if useful.

Jeromefromcn · 2 months ago

Hello — same webview channel error signature, different repro path, cross-linking for visibility.

We hit this exact log line too, but the trigger was different: a third-party
Anthropic-compatible provider emitting one SSE content_block_delta event
per token (thinking-heavy turns → ~6300 events per response). The extension
fell behind the stream (per-event render over Remote-SSH), the CLI blocked
on stdout backpressure, and permission/plan prompts were displayed
minutes-to-hours late — while our Notification hook fired on time, proving
the CLI had already processed the response.

Key data from the affected session:

6400 output tokens → 6314 SSE delta events (~135B each); the official API
batches multiple tokens per delta — 1–2 orders of magnitude fewer events.
Combination matrix: terminal + provider fine, extension + official fine,
extension + provider stalls — only the event granularity varies.
A proxy-level SSE coalescing workaround (merge consecutive same-type
deltas into time-windowed batches) cut the event rate ~3–23x; the prompt
delay went tens of minutes → ~3 min → seconds, with no other variable
changed.
Full writeup with the evidence: #86854.

Both cases point at the same CLI↔webview channel dropping/silencing
responses under stress — in yours the decision never dispatched with no
timeout; in ours responses arrived after the CLI had already dropped the
request. Worth fixing together: batch stream-event rendering on the webview
side, and stop silencing channel errors.

ProteumMach · 25 days ago

Still reproduces on 2.1.259 (VS Code extension native binary, macOS 26 / Darwin 25.6.0, Apple Silicon), permission mode auto, with the sessions driven from another device via Remote Control. Two independent sessions on the same machine hung this way on the same day (11:22 and 16:53 local), while three sibling sessions under the same extension host kept working. Adding the process-level evidence since the earlier reports are mostly log-based.

Fingerprint (same as above)

  • Last transcript line is an assistant Bash tool_use; no tool_result, and none of the internal atis-latch / frame-link / bridge-session entries that appear between tool_use and result in every healthy round of the same transcripts.
  • No child process was ever spawned: the command never started, and no hook was running (one PreToolUse and one UserPromptSubmit hook are configured; neither was alive).
  • Process state S, 0.0% CPU, hours at a time. Not spinning.
  • Machine never slept: pmset -g shows sleep 0, uptime 17 days, no sleep/wake entries in pmset -g log around either hang.

What's different from a plain idle event loop: leaked half-closed sockets

lsof -i on the two hung processes vs. the healthy ones at the same moment:

| session | API connections | Remote Control relay connection |
|---|---|---|
| hung A (stuck ~6 h) | CLOSED | CLOSED |
| hung B (stuck ~40 min) | 3× CLOSE_WAIT, 1× CLOSED, 1× ESTABLISHED | CLOSED |
| 3 healthy siblings | all ESTABLISHED | ESTABLISHED |

CLOSE_WAIT means the far end closed the connection and the client never closed its side, i.e. a request whose connection was dropped without the client noticing or timing out. That matches the "classifier/permission path with no timeout" theory in this issue and the dropped-continuation shape in #94252 and #95354.

Other observations

  • The cross-session messaging socket (/tmp/cc-socks/<pid>.sock) refused messages from a peer session, consistent with the process being stuck inside a tool round.
  • SIGTERM was ignored; SIGKILL was needed.
  • Recovery: claude --resume <id> --remote-control <name> --permission-mode auto from a terminal on the machine picks the transcript up and re-issues the stalled call. Nothing can be done from the remote device, which is what makes this painful when the person is away from the machine.

Happy to share transcript tails privately (they contain project paths).