[BUG] VS Code extension: PreToolUse callback saveFileIfNeeded never resolves — every Read/Write waits 600 s and fails ("host client may be unreachable")

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

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet (closest: #94887 — same error text, different setup)
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code (2.1.281)

What's Wrong?

In a long-running VS Code session, every Read and Write tool call started to fail after exactly 600 s:

PreToolUse hook did not respond before its timeout (host client may be unreachable). The tool call was not executed; other configured hooks may not have completed.

8 of 8 file-tool calls after the first failure (7× Read, 1× Write, different files, over ~2 h) hung for 600 s each and were not executed. Bash kept working normally in the same period (102 calls dispatched without problems). So each file-tool call costs 10 minutes and returns nothing; the agent can only work through Bash.

It is not a user hook. The only settings-level PreToolUse hook matching Read is a command hook with timeout: 10; its output is logged ~0.4 s after the call. The wait is the extension's own SDK hook callback. From extension.js (2.1.281):

hooks: {
  PreToolUse: [
    { matcher: "Edit|Write|MultiEdit", hooks: [(T) => q.captureBaseline(T)] },
    { matcher: "Edit|Write|Read",      hooks: [(T) => this.saveFileIfNeeded(T)] }
  ],
  PostToolUse: [{ matcher: "Edit|Write|MultiEdit", hooks: [(T) => q.findDiagnosticsProblems(T)] }]
}

No timeout is set, so the CLI default (600 s) applies. saveFileIfNeeded awaits vscode.workspace.openTextDocument(uri) and, for a dirty document, save() — also with no timeout. For the hung Write, the other callback (captureBaseline) did run: [DiagnosticTracking] Captured baseline diagnostics for … is logged in the same second. So the CLI ↔ extension callback channel works, and saveFileIfNeeded is the call that never resolves.

Workaround attempt: adding "claudeCode.autosave": false to user settings (this makes saveFileIfNeeded return on its first line) did not help in the already-stuck window. A probe Read 25 s after the change hung for 600 s again, so the stuck extension host apparently never picked up the configuration change. Reload Window has not been tried yet.

What Should Happen?

  • SDK hook callbacks registered by the extension should have a short timeout and fail open ({continue: true}). saveFileIfNeeded is a convenience; it should never block a tool call for 10 minutes.
  • openTextDocument / save() inside it should be raced against a timeout of a few seconds.
  • The error should name the pending callback (e.g. saveFileIfNeeded) instead of "host client may be unreachable", and the extension log should record callback start/end. Currently nothing in the extension log shows which callback is pending.

Error Messages/Logs

Claude VSCode.log (CLI debug output, UTC), first hung Read:

08:13:20.627Z [DEBUG] Hook output does not start with {, treating as plain text      <- user command hook finished
08:23:20.605Z [ERROR] hook failed: core: errorKind=AbortError errorChars=0 (classic.PreToolUse; skipped; what is below it ran in its place)
08:23:20.605Z [DEBUG] managed: its next() rejected below it (classic.PreToolUse); the rejection passes up
08:23:20.605Z [ERROR] hooks chain failed: errorKind=AbortError errorChars=0
08:23:20.607Z [DEBUG] PreToolUse hook timed out (per-hook abort)
08:23:20.630Z [DEBUG] hooks module agents-md@builtin tool.call settled in 600066.8ms (native link, next() included)

Last successful Read: 07:57:28Z ([Stall] tool_dispatch_end tool=Read … outcome=ok durationMs=2).

Possible trigger (time correlation only), from VS Code main.log and the second window's renderer.log:

08:12:29Z  a second VS Code window opened ("Started local extension host with pid …")
08:12:43Z  [warning] No ptyHost heartbeat after 6 seconds
08:12:51Z  Extension host with pid … exited with code: 0   (the second window's)
08:12:51Z  [error] vscode-file: Failed to load resource ~/.vscode/extensions/anthropic.claude-code-2.1.220-darwin-arm64/resources/claude-logo.svg net::ERR_FILE_NOT_FOUND
08:13:20Z  first hung Read in the first window

The extension had auto-updated from 2.1.220 to 2.1.281 earlier that morning.

Steps to Reproduce

Not reproduced deliberately. Observed state: a long session (~7 h) in a VS Code window with two Claude Code tabs, Remote Control connected, auto mode; a second VS Code window was opened. After that, every Read/Write in the first window's session hangs for 600 s. Edit goes through the same callback but was not attempted during the hang.

Claude Model

Opus (claude-opus-5-5, 1M context)

Is this a regression?

I don't know

Claude Code Version

2.1.281 (VS Code extension, darwin-arm64)

Platform

Anthropic API (first party)

Operating System

macOS 26.6.2

Terminal/Shell

VS Code 1.139.0 (extension), zsh

View original on GitHub ↗

3 Comments

TheGeek007 · 19 days ago

Same failure in the Claude desktop app (Code tab) on Windows 11 Pro (build 26200), so it does not look specific to the VS Code extension.

From the session transcripts (~/.claude/projects/**/*.jsonl), measuring the time from tool_use to the error result:

| Time (UTC) | Tool | Waited | Version |
|---|---|---|---|
| 2026-09-25 16:07 | Edit | 600.0 s | 2.1.280 |
| 2026-09-25 16:18 | Edit | 600.0 s | 2.1.280 |
| 2026-09-25 17:42 | Write | 600.0 s | 2.1.280 |
| 2026-09-26 04:12 | Read | 600.0 s | 2.1.280 |
| 2026-09-26 04:25 | Read | 600.0 s | 2.1.280 |
| 2026-09-26 04:38 | Write | 600.0 s | 2.1.280 |

Every one returned PreToolUse hook did not respond before its timeout (host client may be unreachable). The tool call was not executed.

  • There were two sessions in two different projects, and both were affected.
  • No user-configured PreToolUse hooks exist in any settings file (only Stop, SessionEnd, Notification and SessionStart), so the hook that timed out is the host's own.
  • Bash and PowerShell tool calls in the same sessions ran normally, which matches the Edit|Write|Read matcher described above.
  • It is intermittent. On 2.1.281, file tools in a fresh session currently respond instantly.
  • No orphaned hook processes were running afterwards, so this does not look like #96476.

Workaround: after the first 600 s failure, stop retrying file tools in that session (each retry costs another 10 minutes). Either do file work through the shell tool or start a new session.

A timeout of a few seconds on the host's file-save callback, falling through to "not saved" rather than blocking, would turn a 10-minute stall into a non-event.

MarcoPolo483 · 9 days ago

Still reproducing on releases that carry the 2.1.285 fix: macOS 26.5.2, VS Code 1.140.0, extension 2.1.285 then 2.1.289; Windows, Claude Code 2.1.286 (entrypoint not recorded). Changelog 2.1.285: "[VSCode] Fixed every file Read, Write and Edit stalling for ten minutes and then being skipped when the editor stops responding to the extension's automatic save before the tool runs."

Counts, from session transcripts

| Machine, window (EDT = UTC-4) | Version | Timed-out calls | Waited |
|---|---|---|---|
| macOS, 10-04 18:37 to 10-05 07:29 | 2.1.285 | 104, in 7 sessions | 18.7 h |
| Windows, 10-02 to 10-04 (UTC dates) | 2.1.286 | 120, in 48 transcripts | 27.4 h |
| macOS, 10-05 15:06 and 16:39 | 2.1.289 | 4 | 0.7 h |

On macOS 102 of 108 timed-out calls waited 600 s to within a second; six waited longer, up to 2,383 s; 95 were in subagents.

A window reload at 07:57 EDT, which also moved the extension from 2.1.285 to 2.1.289 (not separable), was followed by about seven hours with no timeout: 135 calls completed, two Writes took 433 s and 370 s. Then it returned on 2.1.289: the four timeouts above, plus two Reads that took 339 s and 469 s. During the 16:39 pair of timeouts (a sample at 16:48 EDT) the host read about 100 percent CPU and a 5.2 GB footprint.

New: a join with VS Code's own record (macOS only)

The renderer log writes Extension host (LocalProcess pid: N) is unresponsive. and later ... is responsive.. I joined the 1,475 Read/Write/Edit calls started from 10-04 12:00 to 10-05 18:22 EDT with the 1,521 closed intervals in that span:

  • All 108 timed-out and all 49 slow (over 120 s) calls overlapped an interval.
  • 1,204 of 1,304 completed calls overlapped none; the 33 that started inside an interval all returned only after it ended.

Caveats: intervals average one per 72 s and cover a quarter of the span, clustered by hour, so a 600 s call touches one largely by chance; the completed-call lines are the sharper test. No closed interval exceeds 600 s (longest 398 s); one interval that began at 16:54 EDT, after the last timeout, had no matching 'responsive' line before the host was replaced 2,055 s later. Timed-out calls overlapped a median 80 percent of their wait, the four 2.1.289 timeouts only 0.3 and 1 percent. So a 600 s wait is not one long logged host stall. Correlation, not cause.

Why the host stalls is unknown: VS Code's profiler named an extension in 42 of 1,539 profiles (about 70 s, never Claude Code); 778 ended with no name and no cancel. In the host started at 17:29 EDT, six file-tool calls 50 minutes later took 0.03 to 1.01 s; from 18:27 the extension's own log fell behind the sessions' timestamps by a maximum of 18 s in the 18:27 minute, 43 s at 18:28 and 118 s at 18:30, with no file-tool call in that span.

The 10-second guard in 2.1.289

The extension log warns The editor has not opened <path> after 10 seconds, so the Read tool goes ahead with the file as it is on disk. .... For the two slow Reads that warning was logged within 0.05 s of each Read returning (15:20:17 and 15:49:14 EDT), 339 s and 469 s in, not at 10 s. PreToolUse hook timed out (per-hook abort) is logged 74 times on the 10-04 evening and four times on 2.1.289.

In 2.1.289's extension.js (grep deadlineMs), saveFileIfNeeded races openTextDocument against 10 s and save() against 120 s, both timed by setTimeout inside the extension host. The hook is registered as (k,f,{signal:p})=>this.saveFileIfNeeded(k,p), with no timeout field. I read only 2.1.289, not 2.1.285 or the CLI.

What I tried and saw

One reload, above: confounded with the version change, then slow Writes, then a relapse. Seven file-tool calls of processes that predated it were refused, so stop in-flight work first.

Ask

The warning above was logged seven times on 2.1.289 after the reload; for the two slow Reads it came within 0.05 s of the Read returning, 339 s and 469 s in. So the 10-second bound inside the extension host did not bound those waits; and the four 2.1.289 timeouts overlapped a logged unresponsive interval for only 1.6 s and 6.2 s of their 600 s, so a logged host stall does not account for them either. Why a timer set for 10 s fired at 339 s is not shown by these logs. Ask: time out extension-registered hook callbacks on the CLI side after a few seconds and fail open so the tool still runs; name the pending callback in the error; and when the editor step cannot complete, read the file from disk as the 10-second path already does, rather than dropping the call.

Setup: a large multi-repository workspace with git worktrees under one root (the language server listed 840,000 to 940,000 files); five to ten panel sessions in one VS Code window, often with parallel subagents, over several days. Since 19:05 EDT today claudeCode.autosave is off on macOS, with a language-server exclusion (not separable); no result yet. On Windows the extension host also ran out of heap 14 times on 10-05, a different symptom.

MarcoPolo483 · 9 days ago

Addendum to my comment above: what was pinning the extension host is now identified, and it was not Claude Code. Three loads on the host's single main thread, measured the same evening on the macOS box, each confirmed by removing it:

  1. An extension that activates on workspaceContains:**/*.py (vscjava.migrate-java-to-azure): VS Code's own profiler named it in 22 of 28 attributed unresponsive windows, with the host at about 110 % CPU and 4.7 GB while no Claude Code session was running under it. Uninstalled; the next host start idled at 0.1-0.9 % CPU.
  2. GitHub Copilot Chat's external-ingest index (built into VS Code 1.140, copilot-chat 0.68): a 3-second sample of the pinned host put 1,697 of 2,186 main-thread samples in synchronous node:sqlite StatementSync::Run on a 445 MB codebase-external.sqlite that was being rewritten every few seconds. Turning github.copilot.chat.workspace.codeSearchExternalIngest.enabled off only takes effect at the next host start.
  3. VS Code's built-in Git extension: its own log shows 339 repositories opened in one launch, 337 of them git worktrees under one root, and 451 git commands in a minute. With git.enabled off for the workspace: 0 git commands, 0 repositories opened, 0 unresponsive lines.

This does not change the ask, it sharpens it: the host gets blocked by ordinary third-party work in a large workspace, and a Claude Code file tool then waits the full 600 s hook timeout and loses the call. A few-second CLI-side timeout on extension-registered hook callbacks, failing open to the on-disk read the 10-second path already does, would make that a non-event. A corollary for anyone hitting this: a host pinned with no Claude session under it is the quick proof the load is not Claude Code's, and exthost/<extension>/*.log names the culprit faster than the profiler, which only runs if the stall lasts 5 s.