[BUG] Remote SSH daemon (ccd-cli/2.1.111) exits with code 1 on initialize when hookCallbackIds are present
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?
Environment
- Client: Claude Desktop app on Windows 11 (PowerShell 5.1)
- Server: Ubuntu 24.04 LTS (x86_64), kernel 6.x, on Hetzner VM
- Claude Code version (local daemon): 2.1.111
- Claude Code version (system claude): 2.1.91
- Node.js: v18.19.1 on server
- Auth: Claude Max (OAuth)
Summary
When connecting to a remote SSH machine via the "SSH connection" feature (Claude Code tab → new SSH connection), the daemon at /root/.claude/remote/ccd-cli/2.1.111 exits with code 1 immediately after receiving the initialize control_request, if the payload contains hookCallbackIds.
Reproduction
- Configure an SSH connection in Claude Code tab of Claude Desktop
- Connect to the remote host (auth and SSH work fine — confirmed via
ssh -v) - Send any user prompt (e.g.
ls) - "Claude Code process exited with code 1" is shown, no output visible
Captured payload (intercepted via wrapper script)
\``json``
{"request_id":"s4kd7qgugm","type":"control_request","request":{"subtype":"initialize","hooks":{"PreToolUse":[{"matcher":"mcp__ccd_directory__request_directory","hookCallbackIds":["hook_0"]},{"matcher":"mcp__.*","hookCallbackIds":["hook_1"]}],"Stop":[{"hookCallbackIds":["hook_2"]}]}}}
\
Observations
- The daemon works correctly when invoked standalone (
ssh -t hetzner "claude"works). - The daemon works correctly when the same payload is sent with empty hooks (
"hooks":{}). - stderr of the crashed process is empty (0 bytes) — no error message.
- exit code is always 1.
- Wrapper script that removes
hookCallbackIdsviajqlets the daemon start, but the process then hangs indefinitely (no output, keeps receiving pings but never produces a response) — suggesting the callback IDs are expected by the daemon's RPC loop.
Workaround
Currently using ssh hetzner + claude interactively via tmux instead of the UI feature.
What Should Happen?
SHould establish a ssh connection that doesn't crash at the first input
Error Messages/Logs
Steps to Reproduce
Just creating an ssh connection to a server, using pub key instead of psw
Claude Model
None
Is this a regression?
Yes, this worked in a previous version
Last Working Version
_No response_
Claude Code Version
2.1.111
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
Terminal.app (macOS)
Additional Information
_No response_
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗