Skip to content

/desktop reports success but session never appears in Claude Desktop (sessionId=null + LSHandler misregistration on macOS) #55268

@larskluge

Description

@larskluge

Summary

/desktop reports Session transferred to Claude Desktop to the user, but the session never appears in Claude Desktop. Two distinct bugs are stacked:

  1. URL scheme misregistered against the wrong bundle ID (intermittent, environment-dependent on macOS).
  2. Session ID always resolves to null on the Desktop side, regardless of whether the URL was delivered correctly (architectural — appears to affect all CLI-to-Desktop handoffs).

Result: even when (1) doesn't apply, (2) silently breaks the handoff, and the CLI's success message is misleading.

Environment

  • macOS (Apple Silicon)
  • Claude Code CLI: 2.1.126
  • Claude Desktop: 1.5354.0
  • Claude Desktop's embedded Claude Code SDK (in VM): 2.1.121

Bug 1 — `claude://` URL scheme bound to helper subprocess

`~/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist` had:

```
LSHandlerRoleAll = "com.anthropic.claudefordesktop.helper"
LSHandlerURLScheme = "claude"
```

The `.helper` bundle ID belongs to the sandboxed Electron helper subprocesses (`Claude Helper.app`, `Claude Helper (Renderer).app`, etc.) that don't handle URL events. The main app's bundle ID is `com.anthropic.claudefordesktop` (no `.helper`).

Result: `open "claude://anything"` returns `_LSOpenURLsWithCompletionHandler() failed with error -600 for the URL claude://` (procNotFound). The CLI nevertheless prints `Session transferred to Claude Desktop`.

`lsregister -dump` confirms only the main bundle claims the scheme:

```
path: /Applications/Claude.app
identifier: com.anthropic.claudefordesktop
claimed schemes: claude:
```

So nothing in the static registration explains why the user pref points at the helper. Suspected cause: somewhere during install or runtime, Claude.app calls a setDefaultProtocolClient-equivalent and passes the helper's bundle ID. Could not confirm from outside the app.

Workaround: patch the plist to point at the main bundle:

```bash
python3 - <<'PYEOF'
import plistlib, pathlib, os
p = pathlib.Path(os.path.expanduser("~/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist"))
d = plistlib.loads(p.read_bytes())
for h in d.get("LSHandlers", []):
if h.get("LSHandlerURLScheme") == "claude":
h["LSHandlerRoleAll"] = "com.anthropic.claudefordesktop"
p.write_bytes(plistlib.dumps(d))
PYEOF
killall cfprefsd
```

After that, `open "claude://test"` no longer returns -600 and Claude.app launches correctly.

Bug 2 — `sessionId` always resolves to `null` on the Desktop side

Even when (1) is resolved and the URL is delivered, Claude Desktop's main log shows:

```
[CCD] LocalSessions.setFocusedSession: sessionId=null
```

…on every single `/desktop` invocation. Across multiple `/desktop` calls in different sessions, only one `setFocusedSession` event in the entire log resolved to a real session ID; every other entry (290+ events) is `null`.

Suspected cause: CLI sessions are stored at `/.claude/projects///`, but Claude Desktop's Claude Code runs in an Apple Virtualization Framework VM with its own SDK install at `/Library/Application Support/Claude/claude-code-vm//`. The VM-side Claude Code does not appear to mount or proxy the host's `~/.claude/projects/` directory, so when it tries to load the session ID emitted by the host CLI it can't find the session file → `null`.

This is the more important bug — even if Bug 1 is fixed, Bug 2 silently breaks the handoff.

Reproduce

  1. Start an interactive Claude Code session in terminal.
  2. Run `/desktop`.
  3. Observe CLI prints `Session transferred to Claude Desktop`.
  4. `tail -f ~/Library/Logs/Claude/main.log | grep setFocusedSession` while running step 2.
  5. Observe `sessionId=null`.
  6. Claude Desktop's window does not surface the transferred session.

Suggested fixes

  1. Don't print `Session transferred to Claude Desktop` until Desktop has acknowledged a non-null session ID. Alternatively: `Failed to transfer session — see ~/Library/Logs/Claude/main.log` when `setFocusedSession` returns null.
  2. Verify Desktop's URL handler registers under the main bundle ID, not `.helper`.
  3. Either share the host's `~/.claude/projects/` into the VM, or have `/desktop` upload/import the session into the VM's storage before firing the deeplink.

Additional logs

`detectedProjects` errors (`sqlite3 via disclaimer exited with code 14`) are common in main.log but appear unrelated — they're from Desktop's project-discovery scanning of VS Code/Cursor/Zed databases, not from `/desktop` itself.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:desktopbugSomething isn't workinghas reproHas detailed reproduction stepsplatform:macosIssue specifically occurs on macOS

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions