VS Code extension host becomes unresponsive (1-2.5 min) while claude.exe --resume loads a large session
Environment:
- Claude Code for VS Code: v2.1.181
- VS Code build: commit 93cfdd489c (Windows 11 Enterprise 10.0.26200)
- OS: Windows 11 Enterprise, AzureAD-joined/managed machine
Summary:
After a long-running Claude Code session (many hours, large transcript) and a VS Code window reload, the extension host reports "is unresponsive" for anywhere from ~15 seconds to ~2.5 minutes before recovering on its own. During this window, Task Manager / Get-CimInstance Win32_Process shows a separate claude.exe process (the CLI backend, e.g. .../anthropic.claude-code-2.1.181-win32-x64/resources/native-binary/claude.exe --resume <sessionId> ...) actively running. The freeze duration appears to scale with how much conversation history that session has accumulated -- projects/workspaces with heavy recent Claude Code activity froze repeatedly and for longer; workspaces with no recent Claude Code session history opened instantly.
We spent a full evening incorrectly suspecting an unrelated third-party VS Code extension (ours) before isolating this -- confirmed by disabling that extension entirely and reproducing the identical freeze, then identifying the actual claude.exe --resume process via Get-CimInstance Win32_Process -Filter "ProcessId=<extension-host-pid>".
Every occurrence was paired with this in the Window or Extension Host output log (inconsistently which channel it lands in):
[error] [Window] Canceled: Canceled
at ... Pge.triggerRefresh ...
at ... Failed to load custom agents
Steps to reproduce:
- Run a long Claude Code session in a VS Code workspace (many tool calls / large transcript).
- Reload the VS Code window (or close and reopen it) so the extension reconnects to / resumes that session.
- Observe: "Extension host (LocalProcess pid: N) is unresponsive" in the Window output channel, lasting up to a few minutes, recovering on its own.
- Confirm a claude.exe --resume <sessionId> process is running for the duration (Get-CimInstance Win32_Process | Where-Object CommandLine -like "claude.exe--resume*").
Expected: Resuming a session shouldn't block the VS Code extension host's event loop -- the UI can show a loading state while the resume happens in the background, without making the entire window (including unrelated extensions) appear frozen to VS Code's responsiveness monitor.
Possibly related: #69255 (UI flickering in resumed sessions with longer conversation histories) -- may share the same root cause (resume cost scaling with transcript size), different visible symptom.
Showing cached comments. Read the full discussion on GitHub ↗
4 Comments
The freeze duration scaling with session history size is the JSONL parse cost on
--resume. The session file is a line-delimited JSON log; loading it is O(file size), so a project with weeks of heavy Claude Code activity can accumulate a file that takes minutes to parse on reconnect.The most direct fix is trimming the JSONL.
pip install cozempicthencozempic treat current(dry-run by default, add--executeto apply) strips the common bloat — duplicate tool-use/result pairs, large tool outputs that have already been acted on, superseded state. 2–5x size reductions are typical, and the resume parse time drops proportionally.For ongoing sessions going forward:
cozempic guardsets an automatic threshold so sessions are pruned and restarted before they accumulate back to the problem size.Worth noting: this doesn't fix the VS Code extension host blocking synchronously on the
--resumecall itself — the right architectural fix there is async resume with a loading state, which is on Anthropic to ship. But keeping the JSONL file small is the best available lever right now to minimize how long that blocking window lasts.Resume should not hydrate the entire transcript before the UI can recover.
For large sessions, keep an incremental index: session id, last valid offset, turn summaries, tool-output content refs, and compacted checkpoints. On
--resume, load the index first, stream the tail, and repair the index in the background if offsets are stale.That would make extension-host recovery proportional to recent activity, not total JSONL size. It also gives users a diagnostic: transcript bytes, indexed bytes, stale offset, and time spent parsing.
---
_Generated with ax._
@Necmttn — the incremental index you're describing is the right long-term architecture. Load the index, stream the tail, skip the full hydration. The constraint today is that
--resumeparses the entire JSONL before the UI responds, so sessions with months of history cause that 1–2.5 minute freeze.The complementary lever available now is shrinking the file itself. Most large session JSONLs are 60–80% dead weight — Bash stdout, file-read payloads, Bash error output — that was useful at the time and never referenced again. cozempic prunes those down to stubs, which cuts the parse cost directly since it's O(file size). A 200 MB file that becomes 40 MB loads 5× faster under the current architecture and loads 5× faster under an incremental index too. Both approaches compound rather than compete.
Adding a data point from a related code path, same underlying issue but unbounded: on WSL2 (extension 2.1.214, VS Code 1.117.0), forking a large session pinned the extension host at 100% CPU for 2h+ with no completion until manually killed.
A V8 CPU profile (
kill -USR1→ inspector →Profiler) put 97.6% self time inforkSession(extension.js:273in the shipped bundle). The minified source suggests that for each record, it walks theparentUuidchain with a linearo.find()per step, so O(n²) on JSONL record count (my 59MB session: 7,138 records from ~149 typed messages). Since thewhilewalk has no cycle guard, a corrupt/cyclic parentUuid chain (as reported post-compaction in #46603 / #49996) makes it spin forever.Fix-wise: a visited-set in the walk plus a
Map<uuid, record>lookup would bound it; longer-term, this work probably shouldn't run on the extension host main thread at all (which would also fix this issue's resume freeze).