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"

Status Open
Reported on v2.1.283
Maintainer reply None cached
Activity 2 comments · opened Sep 30, 2026

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 &lt;machine&gt; is offline. If &lt;machine&gt; 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

  1. Run claude remote-control in a repo (I run it as a systemd user service, one per repo).
  2. Start a session from claude.ai and exchange a message or two.
  3. Archive the session from claude.ai. The host logs Session completed … and the child process exits, as intended since #40598.
  4. Unarchive it from claude.ai and send a message.
  5. 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 has status: active, status_bucket: "working", connection_status: "disconnected", worker_status: WORKER_STATUS_UNSPECIFIED.
  • The page opens wss://…/v1/sessions/ws/session_…/subscribe and sends two {"type":"control_request","request":{"subtype":"initialize"}} frames, then only keep_alive. Nothing is received. The user's message is never sent over the socket or any HTTP request. The page appears to wait for initialize to 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

  1. 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 back status: archived. Sometimes the UI keeps showing "This session is archived" until you click Unarchive a second time.
  2. A dead archived session is re-adopted on every host start. On startup the host calls bridge/reconnect for the session recorded in bridge-pointer.json, even though that session was archived weeks ago. The backend re-queues it and immediately sends end_session with reason "archived", so the child exits with code 1 and the host logs Session failed: Process exited with error on every restart.

Workarounds

  • claude remote-control --session-id <id> in the same directory. This starts a separate single-session host.
  • Calling bridge/reconnect for the session, as above. This puts it back into the existing host.

Environment

  • Claude Code 2.1.283 (native), Linux (Debian), claude remote-control server 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

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗