VS Code: chat tab spins forever with no error when the extension host dies
Summary
When the VS Code extension host process dies, the Claude Code chat webview never
notices. The tab keeps animating its "Inferring… / Musing…" spinner
indefinitely — no error, no timeout, no recovery affordance — even though theclaude child process backing it no longer exists.
The webview lives in the renderer process, which does not crash. So the tab
survives, retains its scrollback, and keeps rendering a live-looking stop button
against a backend that is gone. The failure is indistinguishable from normal
work, so you wait indefinitely on a dead tab.
I hit this repeatedly and lost in-progress work each time, only discovering the
sessions were dead by checking ps.
What causes the host to die is not the point
In my case the host was being killed by a V8 heap OOM caused by a different
extension (tracked separately upstream: https://github.com/swiftlang/vscode-swift/issues/2310). That is incidental. Any
extension-host crash exposes this bug, and the extension host is a shared
process that Claude Code cannot control. The bug is that the webview does not
detect its backend is gone.
Evidence
~/Library/Application Support/Code/logs/20260719T104147/main.log:
2026-07-19 11:05:46.757 [error] [UtilityProcess id: 1, type: extensionHost, pid: 29554]: crashed with code 5 and reason 'crashed'
2026-07-19 11:28:09.166 [error] [UtilityProcess id: 2, type: extensionHost, pid: 33842]: crashed with code 5 and reason 'crashed'
2026-07-19 11:43:12.533 [error] [UtilityProcess id: 3, type: extensionHost, pid: 34156]: crashed with code 5 and reason 'crashed'
Session transcripts stop mid-turn, matching the crash times:
cdb27ca9-…last wrote11:06:11(host crashed11:05:46)ce9d29ce-…last wrote11:44:37(host crashed11:43:12)
The UI still showed an active spinner and a stop button ~10 minutes later.
Steps to reproduce
- Open a Claude Code chat in the VS Code panel and start a turn with tool use.
- Kill the extension host while the turn is in flight. Any of:
kill -9 <extension host pid>- drive it to heap OOM
- Command Palette → "Developer: Restart Extension Host"
- Observe the Claude tab: spinner runs forever, stop button still rendered, no
error surfaced.
Confirm the backend is actually gone:
ps -Ao pid,ppid,etime,command | grep native-binary/claude | grep -v grep
If no PID is listed for your session, the tab is dead regardless of what it shows.
Expected behavior
- Detect that the backend process is gone and surface it — an inline error
such as "Claude Code stopped unexpectedly (extension host crashed)" with a
Restart / Resume action. A spinner that runs forever next to a live-looking
stop button is the worst available failure mode: it is indistinguishable from
normal work.
- Make the session resumable from the tab itself, without hunting for a
session UUID on disk.
Actual behavior
Tab spins forever ("Inferring…", "Musing…"), stop button active, no error, work
silently lost.
Environment
| Item | Value |
| --- | --- |
| Claude Code VS Code extension | 2.1.215 (anthropic.claude-code-2.1.215-darwin-arm64) |
| Claude Code CLI | 2.1.133 |
| Telemetry build string | cc_version=2.1.215.408, cc_entrypoint=claude-vscode |
| VS Code | 1.129.1 (commit 8a7abeba6e03ea3af87bfbce9a1b7e48fed567b8, arm64) |
| OS | macOS 26.5.2 (build 25F84) |
| Model | claude-opus-4-8[1m] and claude-opus-4-8 |
| Permission mode | acceptEdits |
CLI invocation (from ps):
claude --output-format stream-json --verbose --input-format stream-json \
--max-thinking-tokens 31999 --permission-prompt-tool stdio \
--setting-sources=user,project,local --permission-mode acceptEdits \
--include-partial-messages --debug --debug-to-stderr \
--enable-auth-status --no-chrome --replay-user-messages
Additional context
Logged at every activation, likely unrelated but noting it:
2026-07-19 11:43:14.634 [error] Error: chatParticipant must be declared in package.json: claude-code
at yBt.$registerAgent (…/workbench.desktop.main.js:1021:73542)
See also: https://github.com/anthropics/claude-code/issues/79246 — transport loss fabricating a user denial in the
transcript. Independent of this one and does not require a host crash to matter.