[BUG] VS Code extension: SDK launch never completes — Interrupted during launch / sdk_stream_ended_no_result (CLI works; macOS 27)
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
- On macOS 27.0 (Apple Silicon), install Claude Code VS Code extension (~2.1.272) with CLI 2.1.27x.
- Open a folder in VS Code (here: a git worktree under a larger repo) and open the Claude Code panel.
- Wait for
Launching Claude on channel: …in the Claude Code Output channel. - Send any prompt once the composer accepts input (e.g.
Test). - Observe: spinner / no assistant tokens for minutes; Output stays in launch with no stream.
- Stop / interrupt →
Interrupted during launch+sdk_stream_ended_no_result. - 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
-pOK); PTY exhaustion (lsof /dev/ptmxholders low); slow UserPromptSubmit/SessionStart hooks when run from a normal shell (<50ms each). SessionStart hook present: iTerm2cc-status(unlikely proven cause; noted for completeness). - Related issues (symptoms overlap, setup differs): #91773 (
sdk_stream_ended_no_resultover Remote-SSH); #82197 (second session never spawns); closed #69600 / #46094 (Interrupted during launchon 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.
3 Comments
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 onPATHis also 2.1.273, so there is no longer any version skew between them. Identical failure: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: xesduwz9k4ologged at 22:12:01 with no correspondingClosing Claude on channel— and looked for the process: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:
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:
So:
launch_claudeis received,Launching Claude on channelis 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 launchis literally accurate: the launch never happened.If that's right,
sdk_stream_ended_no_resultis a downstream symptom and the real defect is a silently swallowed failure (or an unawaited promise) in the extension's spawn path, betweenresolveShellPathand actually starting the binary.---
3. Correction: my original "CLI works" control tested the wrong binary
The original report offered
claude -psucceeding 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 onPATH— 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
cwdof a failing launch:→
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:
stream-json— 5–7 s.cwdset to the failing launch's directory (a git worktree nested under the repo) — 6 s.git worktree listclean,gitdirresolves.SessionStarthooks — 4 fire on this account; all completed in the runs above.SessionStarthook insettings.jsonis a compiled binary bound to 10 hook events with notimeoutset, so it was a prime suspect. Measured with a realistic payload on stdin and no TTY: 209 ms normally, 10 ms underenv -i, 209 ms with iTerm2 variables stripped andTERM_PROGRAM=vscode. It does not block.kTCCServiceSystemPolicyAllFiles(expected; FDA not granted); every other authorization returnsauthValue=1or2.AMFI: '.../resources/audio-capture/arm64-darwin/audio-capture.node' has no CMS blob?andUnrecoverable CT signature issue, bailing outat extension activation, 0.4 s beforelaunch_claude, which looked promising. It isn't: that module isadhoc, linker-signed, and/opt/homebrew/.../fzfhas 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.logand 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 channelon 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 channeland silence has nothing in it.Closing the gap I left open in my previous comment: I said the
cwdaxis 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.cwdis eliminated.Environment: macOS 27.0 (26A428) arm64 · VS Code 1.137.0 (
645f29cc3176500b4b5762ba887cf2a7f0ffdf2c) · extensionanthropic.claude-code-2.1.273-darwin-arm64· CLI onPATH2.1.273. Timestamps America/Edmonton (UTC−6).---
Test folder
Deliberately minimal, to kill three variables at once:
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.).claude/directory — no project settings, no project hooks, noCLAUDE.md.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:
So in Restricted Mode VS Code withholds it entirely. The control pair, same VS Code session, same instant:
| window | folder |
eamodio.gitlensloaded |Anthropic.claude-codeloaded ||---|---|---|---|
| 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
descriptionstring has a typo —"untusted".)---
Result: identical failure in the plain folder
Tally in that window's log, six minutes after the prompt:
Two launches opened, neither closed, neither streamed. No prompt was required to reach the stuck state —
launch_claudefires on panel init; theio_messageat 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
pslines rather than counts, because a count includes thegrepitself and I nearly mis-read it:Control, same command, same second — the pattern mechanism works and does find Claude processes on this machine:
(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_claudereceived →Launching Claude on channellogged → MCP server listening → nothing is ever executed.---
The extension host logs no error at all
I checked
window2/exthost.logacross the whole launch window for anything resembling a failure:No exception, no unhandled rejection, no spawn error, nothing.
ptyhost.logis likewise clean. Whatever prevents the exec is fully silent — which is consistent with a swallowedcatchor an unawaited promise rather than a failingspawn()that would normally surfaceENOENT/EACCES.---
What this eliminates
Combined with the previous comment, the following are now ruled out as the trigger:
cwd.claude/config, project hooks,CLAUDE.mdstream-jsonturn in ~6 s, from the failingcwd, while the panel hangs)SessionStarthooks (measured 209 ms / 10 ms / 209 ms across three environments; all complete in successful runs)audio-capture.nodeAMFI message isadhoc, linker-signed, byte-identical in profile to Homebrew binaries that work fine)The remaining surface is small: something in the extension's launch path between receiving
launch_claudeand 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
The webview emits a
logEventfor channelqmbz8dbui3i1 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 sameChannel not found for logEventwarning 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 channeland silence contains nothing at all, in either the extension's own output channel or the extension host log.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.pythonhang 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.jsof 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:extensions.jsonrecorded this install as"targetPlatform": "darwin-arm64"— the metadata did not match the payload. Presumably that is why VS Code never replaced it, and whycode --install-extension ms-python.python --forceansweredalready installed.b) The macOS 27 upgrade left Rosetta non-functional. From
/var/log/install.logduring the 26.x → 27.0 update:and after first boot:
Since then any x86_64 executable fails. Control: the universal
/usr/bin/truehas an x86_64 slice, and forcing that slice fails too:c) So the Python extension cannot start its locator. From
ms-python.python/Python Locator.log:-86isEBADARCH.Python.logshowsNative locator: Refresh startedtwice, and neverRefresh 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:And
qn$→qi0: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 channelappears 19 times andSpawning Claude with SDK query functionappears 0 times. Control:resolveShellPath, written by the samethis.outputchannel, appears 10 times.---
3. Why no error was ever shown
The only init watchdog is inside the query instance:
It wraps
initializationResult()of an instance that only exists afterBk$()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:Interrupted during launchliterally means "this channel was still inpendingChannels".---
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 newpetisMach-O 64-bit executable arm64, and running it directly printspet 0.1.0, rc 0.I left
claudeCode.usePythonEnvironmentat its default (true) on purpose, so the only variable that changed was the locator binary. After Developer: Reload Window:Spawning234 ms afterLaunching— first time in any retained log.From claude:lines, 0Interrupted during launch, 0Channel not found.…/anthropic.claude-code-2.1.273-darwin-arm64/resources/native-binary/claudechild process exists.---
5. Suggested changes to the extension
qi0activation andresolveEnvironment). A few seconds, falling back to the unmodified env exactly as the existing catch-paths already do. A missing virtualenv onPATHis a far better failure than a dead panel.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.launch_claude, not at spawn. Any pre-spawn stall — this one,IM$'sgitlookups, a slowresolveShellPath— should end in a visible error rather than an indefinitely pending channel.ms-python.pythonis installed but not yet active.Workaround for anyone else hitting this: set
"claudeCode.usePythonEnvironment": falsein 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:
Launchingwith noSpawning, plus a locator error or a hang, points here.---
6. Corrections to my earlier comments
Channel not found for logEventis not a race.logEvent()looks only inthis.channels, never inpendingChannels, 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.audio-capture.nodemessage 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 wheneverms-python.pythonis slow to activate or resolve. That is a hypothesis only — I have not seen their machines — but thepythonEnvMsvalue the extension already records inlaunchTimingwould confirm or rule it out quickly.