Remote Control: unarchived server-mode sessions are never re-dispatched to the running host — messages hang at "Sending…", then "Claude Code on <machine> is offline"
What's wrong
A session served by a long-running claude remote-control host (server mode, same-dir spawn) can't be used again after it's archived and then unarchived from claude.ai. The web UI accepts the unarchive, but a message sent to the session sits at "Sending…" for about 2 minutes and then shows:
Remote Control disconnected Claude Code on <machine> is offline. If <machine> is asleep or lost its connection, this session reconnects when it's back…
The host stays connected and polling the whole time. It is never handed work for the session.
Steps to reproduce
- Run
claude remote-controlin a repo (I run it as a systemd user service, one per repo). - Start a session from claude.ai and exchange a message or two.
- Archive the session from claude.ai. The host logs
Session completed …and the child process exits, as intended since #40598. - Unarchive it from claude.ai and send a message.
- The message sits at "Sending…" for about 2 minutes, then the UI shows the "offline" banner.
This reproduced every time, on 3 different sessions.
Evidence
Host side (claude remote-control --debug --debug-file …): the host polls GET …/work/poll throughout and logs only empty polls ("no work, 100 consecutive empty polls" during the hang). No work item arrives for the unarchived session. In the same environment, a session that isn't archived and has no running process gets its work item within about a second of a message being sent, and the host spawns it normally.
Browser side (HAR from claude.ai):
POST /v1/code/sessions/session_…/unarchive→ 200. The returned session hasstatus: active,status_bucket: "working",connection_status: "disconnected",worker_status: WORKER_STATUS_UNSPECIFIED.- The page opens
wss://…/v1/sessions/ws/session_…/subscribeand sends two{"type":"control_request","request":{"subtype":"initialize"}}frames, then onlykeep_alive. Nothing is received. The user's message is never sent over the socket or any HTTP request. The page appears to wait forinitializeto be answered, but nothing can answer it because no worker was dispatched. - By contrast, sessions that are only idle, for example after a host restart, report
worker_status: "idle"and recover as soon as they're messaged.
Queuing a message another way doesn't help either. claude -p "continue" --cloud cse_… on the unarchived session returns {"ok":true}, but still no work reaches the host.
Re-queuing the session does. Calling the same endpoint the host itself uses at startup and on heartbeat recovery fixes it immediately:
POST /v1/environments/<env_id>/bridge/reconnect {"session_id":"cse_…"} → 200
The already-running host receives the work on its next poll, spawns the session, and the pending message goes through. So the host and the session are both fine. The unarchive path is simply missing this re-queue step.
What should happen
Unarchiving a Remote Control session whose environment is still connected should re-queue it to that environment, as bridge/reconnect does. Alternatively, the web client should send the user's message without waiting for initialize, so the normal "message queues work" path takes over. Either way, the UI shouldn't report the machine as offline while its host is connected and polling.
Two smaller issues seen in the same traces
- Stale read after unarchive. The first
GET /v1/code/sessions/session_…after clicking Unarchive is sent 63 ms after the unarchive POST, before it returns, and comes backstatus: archived. Sometimes the UI keeps showing "This session is archived" until you click Unarchive a second time. - A dead archived session is re-adopted on every host start. On startup the host calls
bridge/reconnectfor the session recorded inbridge-pointer.json, even though that session was archived weeks ago. The backend re-queues it and immediately sendsend_sessionwith reason"archived", so the child exits with code 1 and the host logsSession failed: Process exited with erroron every restart.
Workarounds
claude remote-control --session-id <id>in the same directory. This starts a separate single-session host.- Calling
bridge/reconnectfor the session, as above. This puts it back into the existing host.
Environment
- Claude Code 2.1.283 (native), Linux (Debian),
claude remote-controlserver mode under systemd, same-dir spawn - Client: claude.ai web (Chrome) and Claude desktop app
Related
#90387 (unarchiving never propagates, from Desktop), #40598 (archiving should terminate the host-side process, which is now the behaviour), #88088, #83665
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗