[BUG] VS Code extension: SDK launch never completes — Interrupted during launch / sdk_stream_ended_no_result (CLI works; macOS 27)

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

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet (related but distinct: #91773 Remote-SSH; #82197 second-session spawn; closed #69600 / #46094 similar symptoms on other setups)
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code (claude --version → 2.1.273; VS Code extension package was 2.1.272 at time of the log capture below)

What's Wrong?

In the VS Code Claude Code panel, sessions never finish SDK launch. Auth succeeds (OAuth tokens found in secure storage). The Output channel logs Launching Claude on channel: …, the webview can send user io_messages, but no assistant stream ever starts (no first token). Cancelling yields Interrupted during launch and sdk_stream_ended_no_result (had_error: true). Reproduced with a one-word Test prompt as well as a longer prompt.

Same machine / same account: CLI print-mode works (claude -p 'Reply with exactly: OK' → OK in ~7s). Failure is the extension → SDK subprocess launch path, not Anthropic API/auth.

Also frequent: Channel not found for logEvent: <channelId> (webview events before the channel exists). One launch closed ~3s after Launching with no user interrupt.

What Should Happen?

SDK launch completes; channel becomes ready; user messages stream an assistant reply (or a clear, immediate launch failure with a useful error). Interrupt should not be the only way to discover that launch never finished.

Error Messages/Logs

[info] OAuth tokens found in secure storage
[info] launch_claude … cwd=<workspace> permissionMode=auto thinkingLevel=default_on
[info] Launching Claude on channel: 2gcwlk39553
[info] io_message … text: "Test"
[info] generate_session_title …
… (minutes: no stream / no ready)
[info] interrupt_claude
[info] Closing Claude on channel: 2gcwlk39553
[info] generateSessionTitle failed: Error: Interrupted during launch
[info] log_event sdk_stream_ended_no_result had_error=true message_count=1
[warning] Channel not found for logEvent: 2gcwlk39553

Longer stuck attempt (~78s before interrupt) behaved identically. Separate attempt also logged Failed to get usage Error: Interrupted during launch and Error processing client request: Error: Interrupted during launch. After reload: Loading config cache by launching Claude (no channel)... in parallel with a channel launch; remote session list still works (Fetched 43 remote sessions).

Steps to Reproduce

  1. On macOS 27.0 (Apple Silicon), install Claude Code VS Code extension (~2.1.272) with CLI 2.1.27x.
  2. Open a folder in VS Code (here: a git worktree under a larger repo) and open the Claude Code panel.
  3. Wait for Launching Claude on channel: … in the Claude Code Output channel.
  4. Send any prompt once the composer accepts input (e.g. Test).
  5. Observe: spinner / no assistant tokens for minutes; Output stays in launch with no stream.
  6. Stop / interrupt → Interrupted during launch + sdk_stream_ended_no_result.
  7. Control: in Terminal, claude -p 'Reply with exactly: OK' --output-format text → succeeds.

Claude Model

Not sure / Multiple models (never reached a live turn; launch options in log: thinkingLevel: "default_on")

Is this a regression?

I don't know

Last Working Version

Unknown (in-extension feedback form also failed: would not accept paste into the input field — filing here instead)

Claude Code Version

2.1.273 (Claude Code) CLI; VS Code extension anthropic.claude-code 2.1.272 at log time

Platform

Anthropic API (OAuth / Claude.ai subscription tokens via secure storage)

Operating System

macOS 27.0 (Darwin 27.0.0, build 26A428), arm64

Terminal/Shell

VS Code (Claude Code panel / extension webview — not the integrated terminal TUI). Shell path resolve logged: /bin/zsh → 40 entries. Launch cwd example: a local git worktree. Launch flags from logs: permissionMode: "auto", thinkingLevel: "default_on", freshStartIfUnresumable: false.

Additional Information

  • VS Code: 1.137.0 (645f29cc…), arm64
  • Ruled out locally: missing OAuth; API unreachable (CLI -p OK); PTY exhaustion (lsof /dev/ptmx holders low); slow UserPromptSubmit/SessionStart hooks when run from a normal shell (&lt;50ms each). SessionStart hook present: iTerm2 cc-status (unlikely proven cause; noted for completeness).
  • Related issues (symptoms overlap, setup differs): #91773 (sdk_stream_ended_no_result over Remote-SSH); #82197 (second session never spawns); closed #69600 / #46094 (Interrupted during launch on other Mac setups). This report is local VS Code on macOS 27, CLI healthy, launch never completes.
  • Happy to attach a fuller Output dump or try a diagnostic build.

View original on GitHub ↗

3 Comments

TomCruiseTorpedo · 29 days ago

Follow-up from the reporter. Three updates: the extension update did not fix it, a correction to my own control in the original report, and — the important one — evidence that this is not a stalled launch at all. No child process is ever spawned.

All timestamps America/Edmonton (UTC−6), single host, macOS 27.0 (26A428), VS Code 1.137.0.

---

1. Still reproduces on extension 2.1.273

Updated the extension at 22:10:20 (Extension update check: 2.1.272 -> 2.1.273 (attempt 1): ok). CLI on PATH is also 2.1.273, so there is no longer any version skew between them. Identical failure:

22:11:01.142 [info] Received message from webview: {"type":"launch_claude","channelId":"wlvehlnyd6m",
                    "cwd":"<repo>/.claude/worktrees/<name>","freshStartIfUnresumable":false,
                    "permissionMode":"auto","thinkingLevel":"default_on"}
22:11:01.144 [info] Launching Claude on channel: wlvehlnyd6m
22:11:06.277 [info] Received message from webview: {"type":"io_message", ... "text":"Testing"}
   (39 seconds of nothing — no stream, no error, no child output)
22:11:45.611 [info] Received message from webview: {"type":"interrupt_claude","channelId":"wlvehlnyd6m"}
22:11:45.612 [info] Closing Claude on channel: wlvehlnyd6m
22:11:45.612 [info] generateSessionTitle failed: Error: Interrupted during launch
22:11:45.614 [info] log_event sdk_stream_ended_no_result {"had_error":true,"message_count":1}
22:11:45.614 [warning] Channel not found for logEvent: wlvehlnyd6m

So this is not specific to 2.1.272, and not a skew between the extension's bundled binary and the CLI.

---

2. 🔴 The extension never spawns a child process

This is the part I think matters most, and it changes the shape of the bug.

I caught a launch mid-hang — Launching Claude on channel: xesduwz9k4o logged at 22:12:01 with no corresponding Closing Claude on channel — and looked for the process:

$ ps -axww -o pid,ppid,stat,etime,command | grep 'vscode/extensions/anthropic'
(no output)

Nothing. No process from the extension's own binary directory exists while the extension believes a launch is pending.

That null is control-verified — the identical probe finds other Claude processes on the same machine at the same instant:

$ ps -axww -o pid,ppid,stat,etime,command | grep 'MacOS/claude'
62768   696 S  32:28 /Applications/Claude.app/Contents/Helpers/disclaimer --pgroup -- ...
62769 62768 S  32:28 .../claude-code/2.1.271/claude.app/Contents/MacOS/claude --output-format stream-json ...

Enumerating the extension host's children directly tells the same story. PID 26402 (Code Helper (Plugin)) has children for other extensions — kilo serve, codex, two JVMs, nbexec.sh — and no Claude child at all. Worth noting that this also shows subprocess spawning from the extension host is working in general; other extensions' binaries launch fine in the same process tree at the same time.

The extension's MCP server is up and listening for that session:

$ lsof -nP -iTCP:29712
Code\x20H 26402 ... TCP 127.0.0.1:29712 (LISTEN)

So: launch_claude is received, Launching Claude on channel is logged, the MCP server is listening — and then nothing is executed. The hang is before exec, not a subprocess that starts and fails to stream. Interrupted during launch is literally accurate: the launch never happened.

If that's right, sdk_stream_ended_no_result is a downstream symptom and the real defect is a silently swallowed failure (or an unawaited promise) in the extension's spawn path, between resolveShellPath and actually starting the binary.

---

3. Correction: my original "CLI works" control tested the wrong binary

The original report offered claude -p succeeding as proof the failure is not the binary/auth/API. That control was weaker than I claimed, because the extension does not launch the CLI on PATH — it ships and launches its own copy:

| | path | version |
|---|---|---|
| my original control | ~/.local/bin/claude → ~/.local/share/claude/versions/2.1.273 | 2.1.273 |
| what the extension launches | ~/.vscode/extensions/anthropic.claude-code-<ver>-darwin-arm64/resources/native-binary/claude | matches extension |

I have since tested the bundled binary directly, including the current 2.1.273 one, from the exact cwd of a failing launch:

$ EXT=~/.vscode/extensions/anthropic.claude-code-2.1.273-darwin-arm64/resources/native-binary/claude
$ cd '<repo>/.claude/worktrees/<name>'
$ printf '%s\n' '{"type":"user","message":{"role":"user","content":[{"type":"text","text":"Reply with exactly: OK"}]}}' \
  | "$EXT" -p --input-format stream-json --output-format stream-json --verbose

→ subtype:init → type:assistant → subtype:success, is_error:false, 6 s.

The binary the extension would have launched is healthy, in the SDK's own transport, in the same directory, at the same moment the panel was hanging.

---

4. Eliminated on this host

Each ran clean while the extension panel was failing:

  • Bundled binary (both 2.1.272 and 2.1.273), print mode and stream-json — 5–7 s.
  • Same, with cwd set to the failing launch's directory (a git worktree nested under the repo) — 6 s. git worktree list clean, gitdir resolves.
  • SessionStart hooks — 4 fire on this account; all completed in the runs above.
  • The one SessionStart hook in settings.json is a compiled binary bound to 10 hook events with no timeout set, so it was a prime suspect. Measured with a realistic payload on stdin and no TTY: 209 ms normally, 10 ms under env -i, 209 ms with iTerm2 variables stripped and TERM_PROGRAM=vscode. It does not block.
  • TCC during a failed launch — VS Code is denied kTCCServiceSystemPolicyAllFiles (expected; FDA not granted); every other authorization returns authValue=1 or 2.
  • AMFI / code signing — investigated and ruled out. The log shows AMFI: '.../resources/audio-capture/arm64-darwin/audio-capture.node' has no CMS blob? and Unrecoverable CT signature issue, bailing out at extension activation, 0.4 s before launch_claude, which looked promising. It isn't: that module is adhoc, linker-signed, and /opt/homebrew/.../fzf has a byte-identical signature profile and draws the same AMFI message while working normally. Same class, benign. Flagging it only so the next person doesn't spend time on it.

---

5. On the macOS 27 angle, and why I'm no longer leading with it

I initially suspected the OS upgrade. Timeline, measured from /var/log/install.log and file birth times:

| Time (2026-09-15) | Event |
|---|---|
| 08:17:06 | last boot on macOS 26.6.2 (25G83) |
| 08:22:39 | VS Code extension 2.1.272 installed |
| 10:10:17 | macOS 27.0 (26A428) first boot |
| 11:24:23 | CLI 2.1.272 installed |
| 11:38 | first Launching Claude on channel on record |
| 14:31:27 | CLI 2.1.273 installed |
| 22:10:20 | extension 2.1.273 installed — still fails |

Two changes landed within two hours and neither is isolated; the extension update came first. And the window that would separate them — 08:22:39 → 10:10:17, new extension on the old OS — has no evidence in it: this machine retains only 10 VS Code log session directories and the earliest is 10:56:34, after the upgrade. That's a fact about log retention here, not a finding.

I can't rule the OS out, but it now has to explain why other extensions spawn subprocesses fine from the same extension host, why the same binary runs fine from a shell in the same directory, and why the failure survived an extension update. A silently-dropped spawn in the extension fits all three more simply.

Happy to run anything else, capture a fuller Output dump, or try a diagnostic build. The most useful thing from my side would be a build that logs the spawn attempt and any error from it — right now the gap between Launching Claude on channel and silence has nothing in it.

TomCruiseTorpedo · 29 days ago

Closing the gap I left open in my previous comment: I said the cwd axis was untested at the extension layer, because every launch on record used the same git worktree. Tested now in a plain folder. It reproduces identically. cwd is eliminated.

Environment: macOS 27.0 (26A428) arm64 · VS Code 1.137.0 (645f29cc3176500b4b5762ba887cf2a7f0ffdf2c) · extension anthropic.claude-code-2.1.273-darwin-arm64 · CLI on PATH 2.1.273. Timestamps America/Edmonton (UTC−6).

---

Test folder

/private/tmp/cc-plain-test-221831
└── README.md      (37 bytes)

Deliberately minimal, to kill three variables at once:

  • Not a git repository — git rev-parse --is-inside-work-tree → fatal: not a git repository. (Every previous failing launch used <repo>/.claude/worktrees/<name>, a git worktree nested inside a larger repo.)
  • No .claude/ directory — no project settings, no project hooks, no CLAUDE.md.
  • Brand-new path, no prior session state, opened in its own window via code -n.

---

⚠️ Reproducer gotcha: the extension is absent in an untrusted workspace

Worth recording for anyone else trying this, because it cost me a cycle and looks alarming: on first open the Claude Code icon was not in the activity bar at all.

That is by design, not a symptom. The extension declares:

"capabilities": {
  "untrustedWorkspaces": { "supported": false, "description": "untusted workspaces are not supported" }
}

So in Restricted Mode VS Code withholds it entirely. The control pair, same VS Code session, same instant:

| window | folder | eamodio.gitlens loaded | Anthropic.claude-code loaded |
|---|---|---|---|
| window1 | git worktree (trusted) | yes | yes |
| window2 | /private/tmp/cc-plain-test-221831 (untrusted) | yes | no |

GitLens supports untrusted workspaces, so it loads in both; Claude Code does not, so it loads in neither… until the folder is trusted. After Workspaces: Manage Workspace Trust → Trust, the extension appeared and activated normally. (Minor: the description string has a typo — "untusted".)

---

Result: identical failure in the plain folder

22:25:28.059 [info] MCP Server running on port 41019 (localhost only)
22:25:30.952 [warning] Channel not found for logEvent: qmbz8dbui3i
22:25:30.952 [info] Received message from webview: {"type":"launch_claude","channelId":"qmbz8dbui3i",
                    "cwd":"/private/tmp/cc-plain-test-221831","freshStartIfUnresumable":false,
                    "permissionMode":"auto","thinkingLevel":"default_on"}
22:25:30.953 [info] Launching Claude on channel: qmbz8dbui3i
22:25:36.832 [info] Launching Claude on channel: 5hl68aj0exm
22:25:45.419 [info] Received message from webview: {"type":"io_message","channelId":"5hl68aj0exm", ... "text":"test"}
22:25:45.420 [info] Received message from webview: {"type":"request", ... "type":"generate_session_title", ...}
22:26:03.069 [info] Received message from webview: {"type":"request", ... "type":"webview_focused"}
   (nothing further — no stream, no error, no close)

Tally in that window's log, six minutes after the prompt:

Launching Claude on channel : 2
Closing Claude on channel   : 0

Two launches opened, neither closed, neither streamed. No prompt was required to reach the stuck state — launch_claude fires on panel init; the io_message at 22:25:45 was just me confirming the composer accepts input, as in the original report.

---

Still no child process — plain folder, control included

Same probe as my previous comment, run while both launches were pending. Printing raw ps lines rather than counts, because a count includes the grep itself and I nearly mis-read it:

$ ps -axww -o pid,ppid,etime,command | grep 'vscode/extensions/anthropic'
49486 49482 00:00 /usr/bin/grep -a vscode/extensions/anthropic          ← the grep itself, nothing else

Control, same command, same second — the pattern mechanism works and does find Claude processes on this machine:

$ ps -axww -o pid,ppid,etime,command | grep 'MacOS/claude'
49499 49482 00:00 /usr/bin/grep -a MacOS/claude
62768   696 51:55 /Applications/Claude.app/Contents/Helpers/disclaimer --pgroup -- ...
62769 62768 51:55 .../claude-code/2.1.271/claude.app/Contents/MacOS/claude --output-format stream-json ...

(Those last two are the Claude desktop app, unrelated to VS Code — included purely as proof the probe can find a running Claude when one exists.)

So in a plain, trusted, non-git folder with no project config: launch_claude received → Launching Claude on channel logged → MCP server listening → nothing is ever executed.

---

The extension host logs no error at all

I checked window2/exthost.log across the whole launch window for anything resembling a failure:

$ grep -E '2026-09-15 22:2[5-9]' window2/exthost.log | grep -iE 'error|reject|exception|spawn|ENOENT|EACCES|claude|fail'
(no output)

No exception, no unhandled rejection, no spawn error, nothing. ptyhost.log is likewise clean. Whatever prevents the exec is fully silent — which is consistent with a swallowed catch or an unawaited promise rather than a failing spawn() that would normally surface ENOENT/EACCES.

---

What this eliminates

Combined with the previous comment, the following are now ruled out as the trigger:

  • ❌ nested git worktree as cwd
  • ❌ project-level .claude/ config, project hooks, CLAUDE.md
  • ❌ repository size / nesting depth
  • ❌ prior session state for the workspace
  • ❌ extension version (fails on 2.1.272 and 2.1.273)
  • ❌ extension↔CLI version skew (both 2.1.273)
  • ❌ the bundled binary itself (runs a full stream-json turn in ~6 s, from the failing cwd, while the panel hangs)
  • ❌ user-level SessionStart hooks (measured 209 ms / 10 ms / 209 ms across three environments; all complete in successful runs)
  • ❌ AMFI / code-signing (the audio-capture.node AMFI message is adhoc, linker-signed, byte-identical in profile to Homebrew binaries that work fine)
  • ❌ auth (OAuth tokens found every launch; the same tokens drive successful headless runs)

The remaining surface is small: something in the extension's launch path between receiving launch_claude and actually executing the bundled binary, failing silently and never settling the promise the channel is waiting on.

---

One ordering detail that may or may not matter

22:25:30.952 [warning] Channel not found for logEvent: qmbz8dbui3i
22:25:30.953 [info]    Launching Claude on channel: qmbz8dbui3i

The webview emits a logEvent for channel qmbz8dbui3i 1 ms before the extension host creates that channel, and the host warns that the channel does not exist. It may be harmless telemetry noise. But given the failure is a channel that never becomes ready, a race between webview-side channel identity and host-side channel creation seems worth a look — the same Channel not found for logEvent warning appears in every failing session I have, in both windows and across both extension versions.

---

Happy to run anything further. The most useful thing from this side would still be a build that logs the spawn attempt and any error from it: right now the gap between Launching Claude on channel and silence contains nothing at all, in either the extension's own output channel or the extension host log.

TomCruiseTorpedo · 28 days ago

Root cause found — and fixed on this machine

Short version: the extension awaits the Python extension's environment API with no timeout before it spawns Claude. On this machine that API never answered, because the Python extension's native locator could not execute. The launch parked forever, before spawn(). So no child process, no error, and no 60 s watchdog — which only arms after spawn.

It is not really a VS Code or Claude binary bug on its own. It is an untimed cross-extension await, and anything that makes ms-python.python hang will reproduce it.

Everything below was measured on the reporter's machine (macOS 27.0 26A428, Apple Silicon, VS Code 1.138.0, extension 2.1.273). Code references are to the shipped, minified extension.js of 2.1.273, so identifiers are the minified names.

---

1. The trigger chain on this host

a) An Intel build of the Python extension on an Apple Silicon Mac. This machine was migrated from an Intel MacBook Pro. The migration brought over ms-python.python-2026.4.0-darwin-x64, whose locator binary is Intel-only:

$ file ~/.vscode/extensions/ms-python.python-2026.4.0-darwin-x64/python-env-tools/bin/pet
Mach-O 64-bit executable x86_64

extensions.json recorded this install as "targetPlatform": "darwin-arm64" — the metadata did not match the payload. Presumably that is why VS Code never replaced it, and why code --install-extension ms-python.python --force answered already installed.

b) The macOS 27 upgrade left Rosetta non-functional. From /var/log/install.log during the 26.x → 27.0 update:

shouldPerformRosettaUpdate: YES
rosettaVersionToInstall: (null)
rosettaPackageSpecifiers: (null)

and after first boot:

Rosetta flplugin: daemon port null!

Since then any x86_64 executable fails. Control: the universal /usr/bin/true has an x86_64 slice, and forcing that slice fails too:

$ arch -x86_64 /usr/bin/true
arch: posix_spawnp: /usr/bin/true: Bad CPU type in executable

c) So the Python extension cannot start its locator. From ms-python.python/Python Locator.log:

[info]  Starting Python Locator …/ms-python.python-2026.4.0-darwin-x64/python-env-tools/bin/pet server
[error] Error starting Python Finder …/pet server A system error occurred (spawn Unknown system error -86)

-86 is EBADARCH. Python.log shows Native locator: Refresh started twice, and never Refresh finished.

That is why my earlier suspicion of the macOS 27 upgrade was right in timing but wrong in mechanism. It was not process spawning in general: it was Rosetta disappearing underneath a leftover Intel binary.

---

2. Why that stops Claude Code from ever spawning

In launchClaude() → spawnClaude(), the order is:

// spawnClaude(...)
let N = await IM$(workspaceFolders, cwd, …);              // additional dirs
…
let { pathToClaudeCodeExecutable: M, executableArgs: D, env: O } = this.getClaudeBinary(),
    L = F0("usePythonEnvironment") ?? true, x, R = O;       // F0 = workspace.getConfiguration("claudeCode").get
if (L) { let I = performance.now(); R = await qn$(O); x = performance.now() - I }   // ← parks here
…
this.output.info(`Spawning Claude with SDK query function - cwd: ${Z.cwd}, …`);      // ← never reached
B?.({ pythonEnvMs: x });
let w = (await Bk$({ options: Z })).query($);                                          // actual spawn

And qn$ → qi0:

async function qi0() { …
  let $ = extensions.getExtension("ms-python.python");
  if (!$.isActive) await $.activate();                        // untimed
  … return $.exports }
async function qn$($) {
  let Q = await qi0(); …
  let X = Q.environments.getActiveEnvironmentPath(J.uri);
  let Y = await Q.environments.resolveEnvironment(X);          // untimed — never settles here
  … } catch (X) { return console.warn(…), $ }                  // only catches rejections, not hangs

There are good fallbacks for the failure cases — no extension, no API, rejection — but nothing for the never-settles case.

Verified from the logs: across 19 launches in 9 retained VS Code sessions, Launching Claude on channel appears 19 times and Spawning Claude with SDK query function appears 0 times. Control: resolveShellPath, written by the same this.output channel, appears 10 times.

---

3. Why no error was ever shown

The only init watchdog is inside the query instance:

let H = `Subprocess initialization did not complete within ${Q}ms — check authentication and network connectivity`;
await XY(B.initializationResult(), Q, H)

It wraps initializationResult() of an instance that only exists after Bk$() returns, i.e. after spawn. A launch that stalls before spawn never arms it, so it can wait forever — I watched one sit for 63 minutes.

This also fits #84864's timing table, where the kill lands at spawn +60.0 s: the timer is relative to spawn, not to launch_claude.

Cancelling produces exactly what the original report shows, because interruptClaude() does this:

if (!channels.get($)) { if (pendingChannels.has($)) { this.closeChannel($, true, "Interrupted during launch"); return } … }

Interrupted during launch literally means "this channel was still in pendingChannels".

---

4. Fix, and proof of causation

I replaced the Intel extension with the official darwin-arm64 VSIX of the same version (2026.4.0), fetched from the Marketplace vspackage?targetPlatform=darwin-arm64. Before installing I checked it: the new pet is Mach-O 64-bit executable arm64, and running it directly prints pet 0.1.0, rc 0.

I left claudeCode.usePythonEnvironment at its default (true) on purpose, so the only variable that changed was the locator binary. After Developer: Reload Window:

10:41:47.941 Starting Python Locator …/ms-python.python-2026.4.0/python-env-tools/bin/pet server
10:41:48.008 Launching Claude on channel: qkj3j15cxzk
10:41:48.242 Spawning Claude with SDK query function - cwd: <repo>/.claude/worktrees/<name>, … version: 2.1.273 …
10:41:48.443 Native locator: Refresh finished in 546 ms
  • Spawning 234 ms after Launching — first time in any retained log.
  • 651 From claude: lines, 0 Interrupted during launch, 0 Channel not found.
  • A live …/anthropic.claude-code-2.1.273-darwin-arm64/resources/native-binary/claude child process exists.
  • The panel works.

---

5. Suggested changes to the extension

  1. Put a timeout on the Python-environment step (qi0 activation and resolveEnvironment). A few seconds, falling back to the unmodified env exactly as the existing catch-paths already do. A missing virtualenv on PATH is a far better failure than a dead panel.
  2. Log before the await, e.g. Resolving Python environment…, and log how long it took. Right now the stall happens between two lines that are never written, so the Output channel shows nothing at all.
  3. Arm the launch watchdog at launch_claude, not at spawn. Any pre-spawn stall — this one, IM$'s git lookups, a slow resolveShellPath — should end in a visible error rather than an indefinitely pending channel.
  4. Possibly: skip the Python step entirely when the workspace has no Python files, or when ms-python.python is installed but not yet active.

Workaround for anyone else hitting this: set "claudeCode.usePythonEnvironment": false in VS Code settings. From the code above this should bypass the await entirely. I did not test it here, because I fixed the underlying cause instead.

How to tell if you have this particular variant:

# 1. Does the launch ever reach spawn?
grep -c 'Spawning Claude with SDK query function' ~/Library/Application\ Support/Code/logs/*/window*/exthost/Anthropic.claude-code/*.log
# 2. Is the Python locator healthy?
grep -h 'Error starting Python Finder' ~/Library/Application\ Support/Code/logs/*/window*/exthost/ms-python.python/Python\ Locator.log
# 3. Right architecture?
file ~/.vscode/extensions/ms-python.python-*/python-env-tools/bin/pet

Launching with no Spawning, plus a locator error or a hang, points here.

---

6. Corrections to my earlier comments

  • Channel not found for logEvent is not a race. logEvent() looks only in this.channels, never in pendingChannels, so it warns for any channel that has not finished launching. It is a symptom of the stall, not a cause. Please disregard my "ordering detail that may matter" section.
  • The macOS 27 upgrade was the trigger after all, via Rosetta, rather than a general spawn regression. My previous comment moved away from it too early.
  • The AMFI / audio-capture.node message remains unrelated, as stated.

7. Possible relevance to #80004 / #84864

Those reports show launch_claude → spawn taking 11–16 s before the 60 s watchdog even starts. The same untimed pre-spawn Python-environment await would add exactly that kind of delay whenever ms-python.python is slow to activate or resolve. That is a hypothesis only — I have not seen their machines — but the pythonEnvMs value the extension already records in launchTiming would confirm or rule it out quickly.