Skip to content

[BUG] Remote Control: automatic reconnection doesn't work -- connection drops silently with no recovery #34255

Description

@BluCreator

Preflight Checklist

  • I have searched existing issues and this hasn't been reported yet
  • This is a single bug report (please file separate reports for different bugs)
  • I am using the latest version of Claude Code

What's Wrong?

Problem
Remote Control (/remote-control) silently drops the connection to the Claude iOS app (Code tab) during long sessions. Once dropped, the mobile client becomes completely unresponsive -- messages don't go through and there's no indication on either side that the connection is dead.

The core issue is that the built-in reconnection doesn't work. The connection drops and never recovers on its own. The only fix is to physically walk to the terminal and manually:

Run /remote-control
Select "Disconnect this session" from the interactive TUI menu
Run /remote-control [session-name] again
Notably, this manual disconnect/reconnect cycle always works -- the connection comes back healthy every time after cycling it. This suggests the reconnection logic itself isn't broken at the protocol level; something in the automatic recovery path is failing to trigger what a manual disconnect/reconnect does successfully. The fix may be as straightforward as having the auto-reconnect perform the same teardown/re-establish cycle that the manual flow does.

This defeats the entire purpose of remote control. If you're away from your desk -- which is the whole point of the feature -- you're locked out until you can physically get back to the machine.

The real fix
Remote Control's automatic reconnection needs to actually work. When the connection drops, Claude Code should detect the failure and re-establish the connection automatically, with no manual intervention required. This is the expected behavior for any persistent remote connection (SSH keep-alive, WebSocket reconnect, etc.).

The connection should be resilient to:

Network interruptions (WiFi switching, cellular handoffs)
iOS app backgrounding and foregrounding
Idle timeouts
Transient server-side disconnects
Why CLI flags alone wouldn't solve this
Adding flags like --restart or --reconnect would be nice for scripting, but they don't actually address the problem: you can't type commands when you're not at the computer. That's the whole reason you're using remote control in the first place. The fix has to be automatic.

Workarounds considered (none viable)
Custom slash commands / skills: Can't trigger built-in CLI commands like /remote-control from within a conversation or custom command.
tmux + scripted keystrokes: Theoretically possible (run Claude Code inside tmux, have a cron send keystrokes to disconnect/reconnect), but extremely brittle -- depends on exact TUI menu state, cursor position, timing. Not a real solution.
Cron-based reconnect: Would require non-interactive CLI flags that don't exist (/remote-control --disconnect, /remote-control --reconnect). Even if they did, it's a band-aid for what should be built-in behavior.
Nice-to-haves (secondary to the main fix)
If automatic reconnection is hard to ship immediately, these would at least unblock workarounds:

Non-interactive CLI flags: /remote-control --restart to cycle the connection from a script, enabling cron-based keep-alive
Connection health signal: A heartbeat or status indicator so external tools can detect a dead connection and attempt recovery
Mobile-side indication: Show the user on the iOS app that the connection dropped, instead of silently failing
Use case
I run long Claude Code sessions (hours to a full day) and manage them remotely from my iPhone via the Code tab. This is an incredibly powerful workflow when it works -- I can manage development, run automations, check on projects, all from my phone. But the silent connection drops make it unreliable for anything beyond a few minutes, which undermines the feature entirely.

Environment
Claude Code (CLI)
macOS (Apple Silicon)
Remote client: Claude iOS app, Code tab
Connection typically drops after 15-60 minutes of use

What Should Happen?

Remote Control's automatic reconnection needs to actually work. When the connection drops, Claude Code should detect the failure and re-establish the connection automatically, with no manual intervention required. This is the expected behavior for any persistent remote connection (SSH keep-alive, WebSocket reconnect, etc.).

The connection should be resilient to:

Network interruptions (WiFi switching, cellular handoffs)
iOS app backgrounding and foregrounding
Idle timeouts
Transient server-side disconnects

Error Messages/Logs

Steps to Reproduce

Leave a /remote-control session running and watch it fail to reconnect after a few hours.

Claude Model

Opus

Is this a regression?

No, this never worked

Last Working Version

No response

Claude Code Version

2.1.76

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

iTerm2

Additional Information

No response

Activity

  1. biguscj7 commented on Mar 14, 2026

    @biguscj7

    +1 on @BluCreator issue. Same version of Claude Code / model / iTerm2 and same behavior.

    Terminal window shows 'Remote Control reconnecting'. Running /remote-control does not correct the failed connection.

    Continuing the session from the iTerm2 does not result in reconnecting the session.

  2. cmeinerd commented on Mar 15, 2026

    @cmeinerd

    +1 on @BluCreator issue. Same version of Claude Code / model / iTerm2 and same behavior.

    Terminal window shows 'Remote Control reconnecting'. Running /remote-control does not correct the failed connection.

    Continuing the session from the iTerm2 does not result in reconnecting the session.

    I have the same issue

  3. Wingie commented on Mar 16, 2026

    @Wingie

    Confirming we're seeing this too on Linux (Oracle Cloud, RHEL/aarch64). Two independent sessions disconnect at identical timestamps, confirming server-side. Client stops reconnecting after the 3rd drop (1002 protocol error). No viable workaround — the loop-restart approach doesn't help since it generates a new session each time, requiring manual reconnect on the phone anyway.

  4. SerkanGezici commented on Mar 16, 2026

    @SerkanGezici

    Reproducing this on WSL2 + iOS — v2.1.76

    Environment

    • OS: WSL2 Ubuntu (Linux 6.6.87.2-microsoft-standard-WSL2)
    • Claude Code: v2.1.76
    • Client: iOS Claude app (connecting via Remote Control)
    • Usage: Start session in WSL2 terminal, enable /remote-control, connect from phone

    Symptoms

    1. Silent disconnect while status shows "Active": The statusline shows "Remote Control active" but the phone is actually disconnected. No error, no status change — completely silent.

    2. "Connecting..." hangs indefinitely: After a disconnect, the auto-reconnect kicks in and shows "Remote Control connecting..." but never transitions back to "active". It stays stuck in this state until manual intervention.

    3. Only workaround: Type /remote-control → select Disconnect → type /remote-control again → Connect. This requires physical access to the PC terminal, which defeats the purpose of remote control.

    Frequency

    • Happens every 20-60 minutes during active use
    • Also happens during idle periods (phone screen off / app backgrounded on iOS)
    • The "active but actually dead" case is the worst — you don't know it's broken until you try to send a message from the phone and get no response

    Impact

    This makes Remote Control unusable for its intended purpose (continuing work from mobile away from desk). Every disconnect requires physically going back to the PC to restart the connection.

    Suggested improvements

    1. Auto-reconnect that actually works — when the relay connection drops, the CLI should aggressively retry (exponential backoff) without requiring user intervention via /remote-control toggle
    2. Accurate status indicator — if the relay hasn't received a heartbeat in N seconds, show "disconnected" not "active"
    3. Programmatic reconnect — allow reconnecting without the interactive menu (e.g., a non-interactive flag or API), so users can script a watchdog
  5. henrikalthofknudsen commented on Mar 21, 2026

    @henrikalthofknudsen

    Systemd keep-alive watchdog workaround for Linux users

    Hitting this consistently on Linux (v2.1.81): after a period of idle, the
    service loses its connection to Anthropic's bridge and never recovers. The
    mobile app shows the session as active but messages are never processed.

    How we detect the stuck state:
    Instead of counting log lines (unreliable — normal operation also generates ~1
    line/sec), we check whether the process has an active ESTAB TCP connection to
    Anthropic's servers on port 443. No connection = stuck.

    Watchdog script (~/.local/bin/claude-remote-watchdog.sh):
    #!/bin/bash
    SERVICES=("claude-remote.service" "claude-remote-ha.service")

    for SERVICE in "${SERVICES[@]}"; do
    PID=$(systemctl --user show "$SERVICE" --property=MainPID --value
    2>/dev/null)
    STATE_FILE="/tmp/claude-watchdog-${SERVICE}.fail"

      if [ -z "$PID" ] || [ "$PID" = "0" ]; then
          rm -f "$STATE_FILE"
          continue
      fi
    
      CONNECTIONS=$(ss -tnp | grep "pid=$PID," | grep "ESTAB" | grep ":443" | wc
    

    -l)

      if [ "$CONNECTIONS" -eq 0 ]; then
          if [ -f "$STATE_FILE" ]; then
              echo "$(date): $SERVICE has had no connection for 2 checks (~10
    

    min) — restarting"
    rm -f "$STATE_FILE"
    systemctl --user restart "$SERVICE"
    else
    echo "$(date): $SERVICE no connection — waiting for next check"
    touch "$STATE_FILE"
    fi
    else
    rm -f "$STATE_FILE"
    fi
    done

    systemd timer (runs every 5 minutes):
    [Timer]
    OnBootSec=5min
    OnUnitActiveSec=5min

    Important caveats:

    • We use a 2-check grace period (~10 min) before restarting, to allow the
      process to reconnect naturally after a transient NAT/idle timeout — avoiding
      unnecessary session loss
    • Restarting still creates a new session and loses conversation history — so
      this is a last resort, not a real fix
    • Even without the watchdog, returning to a session after many hours of idle
      often results in a broken/empty session on the mobile side — so the real issue
      is the bridge session not surviving long idle periods end-to-end

    A proper fix in the reconnection logic (or bridge session persistence) would be
    much preferred over any client-side workaround.

  6. twistedmelonman commented on Mar 21, 2026

    @twistedmelonman

    I'm seeing the same exact issue on multiple machines. No network disruption.

    Environment Info

    • Platform: darwin
    • Terminal: iTerm.app
    • Version: 2.1.81
    • Plan: Max 200

    This is not the documented 10-minute network timeout. The local machine remains online, and the CLI process is still running. The disconnect appears to be triggered by something else — possibly an idle timeout, a transient server-side drop, or a cellular/WiFi handoff on the mobile side — but the root cause is unknown because no diagnostic information is surfaced.

    Observed Behavior

    • Remote Control session is established and functioning normally.
    • At some point (trigger unknown), the mobile client shows a yellow "reconnecting" message.
    • The reconnection never completes. The session is unresponsive indefinitely.
    • The only recovery is to physically return to the terminal and manually cycle the connection: run /remote-control → Disconnect → restart with /remote-control [session-name].
  7. djdwyer commented on Mar 22, 2026

    @djdwyer

    Confirming this also occurs on Linux (Ubuntu 22.04 on Azure VM). Same symptoms: silent disconnection after extended session, no auto-recovery, manual disconnect/reconnect cycle fixes it.

  8. jwm1969 commented on Mar 22, 2026

    @jwm1969

    same issue by the time I'm ready to use my remote connection in iOS it's bad/stale; rendering the feature not very useful

  9. Josiah1 commented on Mar 22, 2026

    @Josiah1

    It appears that this phenomenon is widespread and requires urgent improvement.

  10. joelving commented on Mar 23, 2026

    @joelving

    Exactly the same happens on Windows 10 running in Windows Teminal/Powershell 7 and Android on the mobile side.

  11. kb1900 commented on Mar 23, 2026

    @kb1900

    same issue mac os VM with tmux session

  12. whasamatau commented on Mar 24, 2026

    @whasamatau

    Same issue. Windows 11, Windows Terminal, Claude Code 2.1.81, Android app. Session shows "Remote Control reconnecting" and never recovers. Manual disconnect/reconnect from terminal always fixes it, but that defeats the purpose of remote control.

  13. 51 remaining items

  14. lordvyce commented on Aug 14, 2026

    @lordvyce

    i also facing the same issues

  15. AhmedsApps commented on Aug 14, 2026

    @AhmedsApps

    Confirming this is still happening in Claude for windows

  16. abhaya-ui commented on Aug 15, 2026

    @abhaya-ui

    this is still happening on recently updated version of claude code desktop for windows

  17. sgsallhands commented on Aug 16, 2026

    @sgsallhands

    The mechanism: a 3-drops-per-hour circuit breaker turns a transient drop into a permanent one

    This report says reconnection "doesn't work" and that a manual /remote-control cycle always fixes it. Reading v2.1.233, that is exactly right, and there is a specific reason for it: reconnection is not failing at the protocol level, it is being refused by a circuit breaker.

    function v5p() {
      let e = [], t = Number.NEGATIVE_INFINITY;
      return {
        charge(r, n) {
          e = e.filter((i) => r - i < QgS);                          // QgS = 24h
          if (n && e.length >= m5p) return "daily_exhausted";        // m5p = 72
          if (ar(e, (i) => r - i < f5p && (!n || i >= t)) >= p5p)     // f5p = 1h, p5p = 3
            return "hourly_exhausted";
          e.push(r); return "charged";
        },
        noteHealthyBeat(r) {
          let n = e.at(-1);
          if (n !== undefined && r - n >= eyS) t = r;                // eyS = 10 min
        }
      };
    }

    Budgets: 3 reconnects per rolling hour, 72 per 24 hours. A drop only stops counting against you once a healthy beat lands at least 10 minutes after the previous drop. Separately, a single reconnect campaign is { attempts: 14 }, and when it runs out the user-facing reasons are:

    • "could not reach the Remote Control server for about 30 minutes"
    • "the connection to the Remote Control server kept dropping after each reconnect"
    • "the connection to the Remote Control server dropped more than 72 times in 24 hours"

    Why it never recovers

    Combined with the idle-TTL bug in #32982, the sequence is:

    1. Session goes idle → the server expires it ([BUG] Remote Control sessions die after ~20 min idle — server TTL ignores keepalives #32982: the 30s keepalive only runs while a turn is running, and the client reports idle_seconds derived purely from turn activity).
    2. Client notices and reconnects. The session is still idle, so it expires again inside the same window.
    3. Third drop inside the hour → hourly_exhausted → Claude Code stops trying, permanently.
    4. Because the drops arrive faster than the 10-minute healing interval, the budget never refills. Nothing recovers on its own, ever.

    That is why the manual cycle "always works": it does not repair a broken protocol path, it clears a budget the automatic path has exhausted. The original report's intuition — "the reconnection logic itself isn't broken at the protocol level" — is correct, and this is the missing piece.

    Why this is the part that actually hurts

    The failure is silent and permanent and it lands precisely when you are away from the machine — the state Remote Control exists for. From a phone the three failure modes are indistinguishable: a spinner. And the remedy requires physical access to the terminal the feature was supposed to make unnecessary.

    A circuit breaker sized for a flapping connection is the wrong shape for a starved one.

    Suggested fixes

    1. Repeated drops with the same cause (idle TTL) should not consume the budget three times. Charge per distinct cause, or exempt server-side TTL expiry entirely.
    2. When the budget is exhausted, do not stop — fall back to a long slow retry (every 10–15 min, indefinitely) while the local process is alive. There is no cost to retrying against a session the user has not ended.
    3. Surface exhaustion to the remote client. Today the CLI knows the connection is dead while the phone shows a spinner. The remote surface should say "disconnected — reconnect" and offer a button, which is what [FEATURE] Remote Control: manual Reconnect / Disconnect controls on the session row (Desktop and mobile apps) #84987 asks for from the UI side.
    4. Have the automatic path perform the same teardown/re-establish that the manual /remote-control cycle does, as the original report suggests — including resetting the budget, since a user-initiated reconnect is proof the user still wants the session.

    A note for anyone who arrived here blaming tmux

    I checked v2.1.233 for tmux-attachment awareness and there is none: no list-clients, session_attached, or client_attached anywhere in the binary; the only focusOut symbols come from a bundled web UI library; and the heartbeat is a plain setTimeout chain that runs regardless of whether a terminal is rendering. tmux shows up in these reports because tmux is how people leave a session idle, not because it causes anything. On my machine the correlation was perfect and entirely spurious — sibling sessions in the same tmux server, under the same detach events, ran multi-hour autonomous tasks and never dropped, because they were never idle.

    Details of the idle half are in #32982.

  18. howlongjohnson commented on Aug 18, 2026

    @howlongjohnson

    Same failure on Windows, from the Claude Desktop app rather than the CLI. Adding data because the app side has a second, independent timer that is not covered in the reports above.

    Setup

    • Windows 11, Claude Desktop app 1.32352.0 (bundled Claude Code 2.1.229)
    • "Enable remote control by default" is ON. Confirmed in logs: over the 12/08 to 18/08 window, 66 sessions started, 66 got Enabling remote control, 0 failures. Remote control registration itself is 100% reliable.
    • Claude iOS app, Code tab

    What happens

    Every session goes offline after exactly 900 s of inactivity, and cannot be revived from the phone. Tapping a disconnected session returns:

    The remote control session is offline. Reconnect or run /remote-control to start a new session.

    Which requires physical access to the machine, defeating the point of the feature.

    The app-side timer

    %APPDATA%\Claude\logs\main.log:

    2026-08-18 08:03:11 [info] [remote-control] bridge_state: connected
    2026-08-18 08:03:20 [info] [WarmLifecycle:session] Starting idle timeout for local_cef69fb2: 900s
    2026-08-18 08:34:53 [info] [WarmLifecycle:session] Idle timeout reached, disconnecting local_b25a1207
    2026-08-18 08:34:53 [info] [CCD] Pausing session local_b25a1207 (idle_timeout)
    

    A screenshot of the mobile list taken at 08:37 shows that session as Disconnected, three minutes after the pause. So on Desktop the disconnect is not only the server TTL described in #32982, it is also a local WarmLifecycle timer that pauses the session process at 900 s. No user-facing setting exposes it.

    Timer re-fires in a loop

    One session logged Idle timeout reached every 15 minutes for hours after it was already paused:

    2026-08-18 00:25:45 [WarmLifecycle:session] Idle timeout reached, disconnecting local_e7d3903c
    2026-08-18 00:40:45 [WarmLifecycle:session] Idle timeout reached, disconnecting local_e7d3903c
    2026-08-18 00:55:45 [WarmLifecycle:session] Idle timeout reached, disconnecting local_e7d3903c
    2026-08-18 01:10:45 [WarmLifecycle:session] Idle timeout reached, disconnecting local_e7d3903c
    2026-08-18 01:25:45 [WarmLifecycle:session] Idle timeout reached, disconnecting local_e7d3903c
    2026-08-18 01:40:45 [WarmLifecycle:session] Idle timeout reached, disconnecting local_e7d3903c
    

    The timer rearms and refires against an already-paused session instead of being cleared, which looks like a leak rather than intended behaviour.

    Refresh token expiring repeatedly

    Three times in three days, the bridge parked itself and never recovered without a re-login:

    2026-08-15 09:01:29 [error] OAuth token refresh failed: status=400, {"error": "invalid_grant", "error_description": "Refresh token expired"}
    2026-08-16 23:34:49 [error] OAuth token refresh failed: status=400, {"error": "invalid_grant", "error_description": "Refresh token expired"}
    2026-08-17 09:03:10 [error] OAuth token refresh failed: status=400, {"error": "invalid_grant", "error_description": "Refresh token expired"}
    2026-08-17 09:03:10 [warn]  [sessions-bridge] OAuth stale-session (session_stale_relogin); parking bridge until re-login
    

    This account is a Max plan shared across three devices, so refresh token rotation between devices is a plausible cause. Matches what #69543 reports about bridge-state.json going stale on Windows.

    What would fix this from a user standpoint

    1. A remote "wake" action: let the phone restart a paused local session, since the process manager is still running on the machine.
    2. Make the 900 s WarmLifecycle timeout configurable, or skip it entirely while remote control is connected.
    3. Clear the idle timer once a session is paused, rather than rearming it every 15 minutes.
  19. jumbo-dijital commented on Aug 24, 2026

    @jumbo-dijital

    Confirming this is still happening on Claude Code for Mac OS X

  20. pstayets commented on Aug 26, 2026

    @pstayets

    If you need something that holds up while this gets fixed, one option, shell.online, MIT, single binary. Disclosure, I work on Pilot Protocol, which develops it. shell claude runs claude in a detached local PTY and prints a browser link, the process keeps running whether or not anything is connected, so a dropped phone connection is just reloading the tab. No pairing, no server-side session registry, and it works on any plan since it wraps the CLI. I tested the detach and reconnect mechanics on macOS and Linux today. Limits, the link is a bearer credential, anyone holding it can view and type, and the relay is Cloudflare, not E2E.

  21. aishaorganicsjp commented on Aug 27, 2026

    @aishaorganicsjp

    I'm experiencing the same issue.

    My Mac stayed awake and connected to the network all night without sleeping,
    but when I checked the Claude iOS app in the morning, some of my sessions
    showed as "disconnected." Auto-reconnect did not happen — the only way to
    restore the connection was to run /remote-control again on the Mac itself.

    This is a serious problem for me because I'm currently traveling without
    physical access to my Mac. If this happens while I'm away, there's no way
    to recover the session from my phone at all, and I'm completely stuck until
    I get back to my Mac.

  22. web3dev1337 commented on Aug 27, 2026

    @web3dev1337

    I havn't even been using the RC, and got the error... ● Remote Control disconnected — Transport recovery exhausted (code 4093) — run /remote-control to reconnect

  23. samd1993 commented on Aug 28, 2026

    @samd1993

    This has been happening for months now. Really wish there was a fix. Currently my biggest gripe with Claude is that we don't have seamless integration across devices.

  24. chedly99 commented on Sep 1, 2026

    @chedly99

    Also seeing this on Windows (Claude Code v2.1.252, npm-global install), not just iOS/macOS adding for cross-platform visibility.

    Ruled out on my end:

    What I'm seeing: a fresh claude --remote-control --background session shows /rc active locally (the CLI-to-relay handshake succeeds), and I also hit an explicit Remote Control host unreachable (computer_unreachable) error on a separate attempt. Either way, Desktop's Code tab never reflects any session old or brand new as connected.

    So on this setup the break looks like it's specifically in relay→Desktop sync rather than CLI→relay connectivity.

    Any help with this ? i really want to have all my sessions back on the desktop app

  25. delr commented on Sep 19, 2026

    @delr

    Still reproduces on 2.1.278 (Windows). Nothing in the changelog through 2.1.278 touches the auto-reconnect path.

    The health signal already exists. ~/.claude/sessions/<pid>.json carries bridgeSessionId next to status and updatedAt, An external watcher can already tell which sessions are meant to be remote-controlled. (Careful with updatedAt though — it's a last-activity stamp, not a heartbeat: It can't be used as a liveness check.)

    What's missing is a recovery entry point. --remote-control [name] only applies at launch and /remote-control is a TUI command, so neither a hook nor an external script can re-establish the bridge for a running session. That leaves killing and relaunching, which loses live session state (armed background shells, session-scoped permission grants) even though the transcript itself resumes fine.

    A runtime equivalent of the launch flag — anything callable that re-runs the connect path on the current session — would make the external workaround unnecessary.

  26. fazaamal commented on Sep 20, 2026

    @fazaamal

    Temp workaround while this is open — it automates the manual /remote-control reconnect from the machine itself, so a dropped bridge comes back without havign to be at the machine. Tested on Claude Desktop for macOS 2.2553.1. Scope: Code chats started in the desktop app (Code tab) on that machine.

    The app's built-in DevTools console exposes the internal call the manual flow uses — no debug port needed (the app refuses --remote-debugging-port anyway):

    1. echo '{"allowDevTools": true}' > ~/Library/Application\ Support/Claude/developer_settings.json, then restart Claude.
    2. Cmd-Opt-I → main window → Console (type allow pasting + Enter once if it blocks the paste).
    3. Paste a small script that, every few minutes, runs this for each grouped chat:
    await LS.warmSession(id);                 // LS = window["claude.web"].LocalSessions
    await LS.toggleRemoteControl(id, true);

    The tell that matches this bug: a bare toggleRemoteControl(id, true) on an idle session is refused with "Remote Control requires an active session". Calling warmSession(id) first makes it succeed, and it re-registers the bridge with no message posted and no turn spent (session stays idle, remoteControlState → on). So the auto-reconnect likely just needs to warm + re-enable on drop.

    Unofficial / internal APIs, and it dies on a full app restart (re-paste). Full script + README: https://github.com/fazaamal/claude-desktop-remote-control-keepalive

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingplatform:iosIssue specifically occurs on iOSplatform:macosIssue specifically occurs on macOS

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions