[BUG] Desktop: Remote SSH session hangs after `Passing plugin(s) to SDK`, no server.spawn RPC ever issued
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Claude Desktop on macOS 26.3.1 hangs indefinitely when starting a Remote (SSH) Claude Code session.
The hang occurs immediately after Desktop logs [CCD] Passing N plugin(s) to SDK. After that line the SDK never proceeds to spawn the remote CLI — no server.spawn RPC is ever sent to the remote server --bridge. All worker threads sit idle in mach_msg, so it is not a CPU hang but an async await that never resolves.
Reproducible every time, including with:
- a completely fresh
~/Library/Application Support/Claude/(full re-login), - zero remote MCP connectors (single plugin: skills),
- empty session persistence.
A direct SSH + claude CLI workflow on the same remote host works normally, which isolates the bug to the Desktop-side SDK → CLI spawn path (not the remote host and not the network itself).
What Should Happen?
After [CCD] Passing N plugin(s) to SDK, the Desktop SDK should either:
- issue a
server.spawnRPC over the bridge and startccd-clion the remote within a few seconds, OR - fail with a clear timeout / error surfaced in the UI so the user can act on it.
An indefinite, silent hang with no error, no timeout, and no UI feedback is the worst failure mode — the user cannot tell whether work is progressing, queued, or dead.
Error Messages/Logs
# Mac side main.log — the hang point (reproduces every attempt)
[info] Starting local session local_XXXXXX in /home/tama/ai-agent-team
[info] [SSH] Using remote spawn function for session ... (cli: /home/tama/.claude/remote/ccd-cli/2.1.111)
[info] [CCD] Using skills plugin at: .../local-agent-mode-sessions/skills-plugin/...
[info] [CCD] Passing 1 plugin(s) to SDK (skills: 1, remote: 0, local: 0)
[info] [EventLogging] Flushing N events ← periodic flush continues, but no more real progress
[info] LocalSessions.checkGhAvailable: cwd=... ← periodic repeat only; no session ever starts
# Mac side ssh.log — network-interface flap correlates with hangs
[info] [remote] network-interface change detected; probing SSH controllers
[info] [remote] network-interface change detected; probing SSH controllers
...
# Earlier incident showed a 15-minute handshake timeout from the same cause:
[error] [SSH2Connection] Connection error: Timed out while waiting for handshake
[error] [RemoteServerController] Connection failed (899990ms, trigger: warm_up)
# Remote side bridge RPC log — shows Desktop connects fine, then goes silent:
[Server] RPC request: method=server.capabilities, id=1 → ok
[Server] RPC request: method=server.ping, id=2 → ok
[Server] RPC request: method=files.list, id=3-5 → ok
[Server] RPC request: method=files.read, id=6-7 → ok
(silence — no server.spawn RPC ever arrives)
Steps to Reproduce
- macOS 26.3.1 (arm64 Apple Silicon) with Claude Desktop 1.3883.0.
- Configure a Remote SSH host for Claude Code (Hetzner VPS, Linux amd64, ~300ms RTT).
- Launch Desktop. SSH handshake + bridge channel open in ~15s (logs
[BinaryDeployment] Bridge channel opened,Connected to remote server). So far, so good. - Send any prompt (even an empty
ping) to kick off a session. Desktop logs:
Starting local session local_XXXXXX in <cwd>
[SSH] Using remote spawn function for session ... (cli: ~/.claude/remote/ccd-cli/2.1.111)
[CCD] Using skills plugin at: ...
[CCD] Passing 1 plugin(s) to SDK (skills: 1, remote: 0, local: 0)
- UI spins forever. No error. No further real log entries — only periodic
EventLogging FlushingandcheckGhAvailablerepeats. On the remote,remote-server.logconfirms noserver.spawnRPC ever arrives.
Persists after each of the following, tried in isolation:
- clearing
~/Library/Application Support/Claude/local-agent-mode-sessions/ - clearing
claude-code-sessions/ - clearing
claude-code/andclaude-code-vm/CLI caches - clearing
local-agent-mode-sessions/skills-plugin/ - moving the entire
~/Library/Application Support/Claude/aside and re-logging in - disabling every Connector on claude.ai/settings/connectors (plugin load = skills only, remote: 0)
- swapping the Desktop-deployed binary at
~/.claude/remote/ccd-cli/2.1.111with the content of the user's native~/.local/share/claude/versions/2.1.119(still hangs — rules out "version-specific to 2.1.111")
Claude Model
Not sure / Multiple models
Is this a regression?
Yes, this worked in a previous version
Last Working Version
Unknown — Desktop 1.3883.0 initially worked for Remote SSH sessions to the same host earlier today (and in previous days/weeks); the hang started appearing without an obvious trigger, possibly correlated with a macOS network-interface flap event.
Claude Code Version
2.1.119 (Claude Code) — user's native install used by direct SSH, which works fine 2.1.111 — Desktop-deployed CLI at ~/.claude/remote/ccd-cli/2.1.111, which hangs
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Other
Additional Information
sample(1) of hung Desktop process
All threads idle in mach_msg — no stuck CPU loop, consistent with an unresolved async await:
- Main thread —
[NSApplication run] → _nextEventMatchingEventMask → _CFRunLoopRun → mach_msg2_trap(100% idle). - libuv-worker × 4 — all in
mach_msg. - tokio-runtime-worker × 8 — all in
mach_msg. - V8Worker × 3 — all in
mach_msg.
Experiment: CLI version swap rules out version specificity
Replaced the Desktop-deployed ccd-cli/2.1.111 binary with the content of the user's working versions/2.1.119 (filename kept as 2.1.111 so Desktop's [BinaryDeployment] CLI v2.1.111 cached path accepts it). Still hangs identically. This rules out "older CLI version" as the root cause and points at the Desktop → CLI spawn bridge, or at state/handshake happening before the child process is actually invoked — consistent with the fact that no server.spawn RPC is ever sent.
Correlated signal: network-interface flapping
Mac ssh.log shows [remote] network-interface change detected; probing SSH controllers events in the same window as hangs, including during an earlier separate 15-minute SSH handshake timeout (Connection failed (899990ms, trigger: warm_up)). Hypothesis: in-flight SSH/HTTP calls spawned by the SDK are orphaned on interface flap and lack a watchdog timeout, so the SDK's internal await never settles.
Related (but distinct) issues
- #52734 — Desktop SSH session hangs 3–10 min on "Starting session…" after a
utunnetwork-interface flap. Same Desktop 1.3883 and same deployedccd-cli/2.1.111, but the hang is beforePassing plugin(s) to SDK(in[remote] probing SSH controllers) and recovers on its own after a few minutes. This report is different: hang is afterPassing plugin(s) to SDK, noserver.spawnRPC is ever issued, and it never recovers. - #52122 — flagged by auto-triage as a possible duplicate of #52734.
Common thread across all three: Desktop 1.3883 + remote-spawn pipeline on macOS, different phases of the pipeline stuck.
Full logs and diagnostics
Complete main.log, ssh.log, sample output, and remote remote-server.log are available in a private GitHub repo. Happy to share directly with Anthropic engineers — please comment or DM for access.
The logs contain per-account identifiers so are not included inline here.
Environment (extended)
| Component | Version |
|---|---|
| Claude Desktop | 1.3883.0 |
| CCD / Claude Code CLI (Desktop-deployed) | 2.1.111 |
| Claude Code CLI (native, working via direct SSH) | 2.1.119 |
| macOS | 26.3.1 (25D2128), arm64 Apple Silicon (MacBook Air) |
| Node (bundled in Electron) | 24.14.0 |
| Remote host | Linux amd64, ~300ms RTT from client |
| Remote claude-ssh binary | 9a871e263f5ad97516c97c8c8129f94990635ae7 (built 2026-04-21) |
6 Comments
Found 2 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
This is a strong remote-startup bug because it isolates the failure to a very specific bridge boundary: Desktop reaches the point of handing plugins to the SDK, but never crosses into the actual remote
server.spawnstep. That means the problem is not generic SSH reachability or remote CLI viability; those have already been partially ruled out by the direct SSH +claudesuccess path.The absence of timeout or surfaced error makes it especially costly. Users are left in a state where nothing progresses and nothing explains itself, which is one of the hardest classes of remote orchestration failure to reason about.
From the operator perspective, this is not just a hang. It is a dead start path on the Desktop-side remote-session control plane.
Thanks @0xbrainkid — your framing captures it exactly. "Dead start path on the Desktop-side remote-session control plane" is a much better description than my original wording. Happy to update the issue text if helpful.
On the auto-triage bot: neither #52122 nor #25664 is a duplicate of this one, though #25664 is genuinely adjacent and worth reading alongside.
ccd-cliis spawned on the remote and then hangs trying to load local macOS plugin paths (/Users/<user>/.claude/plugins/cache/...) that don't exist on the remote filesystem. The hang is downstream ofserver.spawn, inside the child CLI process, and at least one plugin path is present in the command line.ccd-cli/2.1.111):ccd-cliis never spawned. Noserver.spawnRPC ever reaches the remoteserver --bridge(confirmed via the remote-side RPC log — onlycapabilities,ping,files.list,files.readarrive, then silence). The hang is before any child process exists. The plugin count at the hang point isskills: 1, remote: 0, local: 0— i.e. no local or remote MCP plugins in play, just the built-in skills plugin.So #25664 and #52790 are at different phases of the same Desktop → remote-spawn pipeline, with different states at the moment of hang. They may share a root-cause area (plugin/handshake handling around the Desktop→SDK→ccd-cli boundary), but the user-visible failure is different and the fixes are likely independent.
Please don't auto-close as a duplicate — treating these as separate will surface both phases of the pipeline to the fix owner.
Private logs +
sample+ RPC trace already prepared in a private repo (mentioned in the body). Happy to add Anthropic engineers as collaborators.Reproducing this on Windows 11 (MSIX), same
Passing plugin(s) to SDKhang with the sameclaude-ssh9a871e263...build on the remote. Cross-platform, not macOS-specific.Regression pinpointed to MSIX auto-update at 2026-04-24 14:48:23 UTC
Client
main.log:Client
ssh.log—ClaudeSSHManagercommit flipped across this restart:Every SSH session before 14:48 on the same Windows machine, same VPS, same user, worked and logged the full
[RemoteProcess:…] Creating process / Spawning / Spawn confirmedsequence. Every session after the update stops at[RemoteServerController] Connected to remote serverwith no[RemoteProcess]line ever emitted — exactly @Tama831's "noserver.spawnRPC ever issued" on macOS. MSIX update is the only change; no VPS-side changes, no config changes.Windows-side hang log, matching the macOS sequence
The
SSH plugin sync failedwarning fires only from the socket-cleanup handler, i.e. after the user kills the app. The fallback pathcontinuing without synced pluginsis aspirational in the log text but never actually exercised during normal runtime — the awaited Promise never resolves, so spawn is blocked indefinitely. Adding a real timeout with UI feedback (per @Tama831's ask #2) is urgently needed.VPS-side RPC trace — identical to @Tama831's
/home/cyb/.claude/remote/remote-server.log:Capabilities, ping, two
files.reads (folder browser) — then 50s of silence — then client-side close. Noserver.spawn, no plugin-sync method ever reaches the server. Same pattern as the macOS report.Environment
| Component | Value |
|---|---|
| Claude Desktop | 1.3883.0.0 (MSIX, Microsoft Store /
Claude_pzs8sxrjxfjjc) || Desktop CCD | 2.1.111 |
| OS | Windows 11 Home 10.0.26200 |
| Remote | Ubuntu VPS, amd64, non-root user (
cyb@…) over Tailscale || Remote
claude-ssh|9a871e263f5ad97516c97c8c8129f94990635ae7(uploaded by the updated desktop on 2026-04-24 14:49:06) || Remote
ccd-cli| 2.1.111 (unchanged from before the regression) |Additional cross-checks
ssh + claude).--allow-dangerously-skip-permissionsroot issue (#36739).%LOCALAPPDATA%\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\Claude\local-agent-mode-sessions\skills-pluginis useless — on next launch the app re-downloads 5 skills from the cloud profile and logs[SkillsPlugin] Delta: 5 to download, 0 to remove, then hangs withPassing 1 plugin(s) to SDKagain. Skills can't be fully disabled from the user UI (visible UI lists only 1 of the 5 counted by the client). Only fix available to users right now is the VSCode remote path or downgrading the desktop app.Confirms this is a cross-platform Desktop regression in the 2026-04-21
claude-sshbuild (9a871e263...), triggered for Windows users by the MSIX auto-update pushed on 2026-04-24. Please don't auto-close as duplicate.Thanks @cyb213 — this is a major corroboration. To help maintainers avoid triaging this as OS-specific or user-config noise, summarizing the combined evidence from both reports, plus related same-window issues.
Established facts from the combined reports
ccd-cli/2.1.111. Desktop side is macOS 26.3.1 and Windows 11 Home 10.0.26200 respectively. The only shared variables are Tailscale + Ubuntu VPS + Desktop remote SSH; everything else is independent (Tailscale itself is addressed in "Cross-reference with same-window issues" below).claude-ssh.cee98937dc257e6af64e712d71dbe4497eb82452(built 2026-04-14T16:53:35Z)9a871e263f5ad97516c97c8c8129f94990635ae7(built 2026-04-21T17:07:27Z)claude-sshfrom good to bad, and the hang started on the very next session — same VPS, same user, nothing else changed. A bisect across the diff between these two builds should isolate the change.server.spawnon the Desktop-app side. On the same VPS, same user, at the same time, Claude Code invoked via the VSCode remote extension works end-to-end. VPS-sideremote-serverlogs on both reports showserver.capabilities+server.ping+ a couple offiles.readRPCs, then silence — the client never issuesserver.spawnat all. The remote server stays healthy and idle; the client never reaches the point of sending that RPC (so the health of the server-sideserver.spawnhandler itself can't be judged from this observation, since no call arrives).SSH plugin sync failed; continuing without synced plugins: No response from serverwarning is observed only from the socket-cleanup handler (i.e., when the user force-quits the app). During normal execution, neither that warning nor thecontinuing without synced pluginsbehavior that should follow it appears; the plugin-sync awaited Promise neither resolves nor rejects, spawn is blocked indefinitely, and no UI feedback is shown. Without having read the source I won't claim this definitively, but the log behavior suggests the happy-path fallback branch is unreachable at runtime.[SkillsPlugin] Delta: 5 to download, 0 to removein the logs shows 5 skills are synced from the cloud profile. Because of this gap, users have no in-app way to disable the skill that's triggering the hang.Cross-reference with same-window issues
To avoid this being treated as an isolated case, listing related recent reports in order of relevance.
awaitthat never resolves." Related siblings from the same rewrite: HTTP MCP timeout (#50289) and Windows subprocess-init regression (#50559).claude-sshmoving from9e5781db→cee98937removed the password-auth fallback. Combined with the present report, this meansclaude-sshhas shipped at least two behavior-breaking changes in roughly two weeks (9e5781db → cee98937 → 9a871e263).server.spawnis never issued" shape as this issue; the trigger differs (#43852 involves a username containing a space, over a ZeroTier overlay), but the lineage — "the client-side exec/spawn path silently fails" — lines up.Starting session…hangs for 3–10 minutes after a utun flap. This issue is a permanent hang, so the symptom is different, but as a nearby-in-time bug in the same log phase the two may be related.Across this issue (Tailscale), #51021 (Tailscale), and #43852 (ZeroTier), the common thread is VPN/overlay transport + silent failure on the subprocess/spawn path — not a Tailscale fault per se, but a situation where the latency/packet pacing of a VPN overlay appears to expose a race in the post-rewrite spawn logic. Taken together, the circumstantial evidence suggests this isn't an isolated bug but one sitting in the blast radius of the 2.1.113+ native-binary spawn rewrite and the recent
claude-sshchanges (causation pending a proper bisect).Reproduction, mitigations, and resolution criteria
Minimum repro config (for internal reproduction):
claude-ssh 9a871e263...With that, the hang should reproduce after
Passing 1 plugin(s) to SDKat session start, with no spawn ever following. If it doesn't reproduce, variables worth varying: skill count, substituting a direct SSH path for Tailscale, and the cloud profile's plugin configuration.Current mitigations. Realistic options are (a) switching to VSCode Remote, or (b) downgrading the Desktop app to a build older than the 2026-04-21
claude-ssh. (a) is functionally degraded — Desktop's integrated features (skills / plugin UI / cowork / file pane) are unavailable. (b) is possible on macOS if an older DMG is on hand, but on Windows MSIX, pinning to an older version is effectively impossible for end users given how the Store distributes it, which leaves Windows users with only VSCode Remote. Deleting the localskills-plugindirectory has no effect — the app re-downloads from the cloud profile at next launch.Resolution criteria (what we'd consider sufficient to close this issue):
claude-sshbuild introduces an explicit timeout on the plugin-sync await.continuing without synced pluginsfallback branch is reachable at runtime.Preventive suggestions (optional).
claude-sshhas shipped at least two behavior-breaking regressions in ~2 weeks (#48565 + this one), and end users currently have no way to defer the auto-update. Would be grateful if the team could look at (i) a kill switch / rollback path when a breaking regression is detected, (ii) splitting the Desktopclaude-sshbuild channel into stable / beta, and (iii) adding client-side telemetry on critical-path awaits like plugin-sync (timeout counts, fallback-branch hit rate) — so the next silent hang of this shape surfaces quickly with a measurable blast radius.Evidence bundle
sampledumps of the hung process, and VPS-sideremote-server.logRPC trace live in the private repo linked from the original post. Happy to grant access or mirror the relevant excerpts into this issue if it helps a maintainer — just say the word.main.log/ssh.logexcerpts into the same repo alongside the macOS artifacts so there's a single place for anyone debugging this to pull both platforms' traces. Happy to set up a folder for you or accept a PR — whichever you prefer.---
Please don't auto-close as duplicate of the older SSH-flakiness issues (#52734, #52122). Could a maintainer share where triage stands against the
9a871e263 ↔ cee98937claude-sshdiff and the broader 2.1.113 native-binary spawn rewrite? This currently blocks the Desktop remote Claude Code workflow for affected users with no in-app mitigation, and we'd appreciate triage priority reflecting that.This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.