[BUG] Remote Control (mobile): session silently hangs mid-execution; only local Esc recovers it — no remote unstick mechanism
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported as a bug yet (related: #47127 feature request for Cancel button, #28508 AskUserQuestion sync bug — both distinct from this)
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code
What's Wrong?
When using Claude Code via Remote Control (claude.ai/code) from a mobile browser, the CLI session on my laptop silently enters a frozen state mid-execution and becomes permanently unresponsive to any input from the mobile client. The only recovery mechanism is pressing Esc (or any key) on the local terminal — no action from the mobile side can unstick it.
This is distinct from:
- #47127 (feature request for a Cancel button to interrupt a visibly running tool)
- #28508 (
AskUserQuestionresponses from mobile not propagating to CLI)
In my case there is no visible tool call in progress, no AskUserQuestion, no rate limit, no API error, no obvious trigger. The session just stops advancing after 2-4 normal message exchanges, and from the mobile client it looks like every new message is being sent but nothing ever comes back.
Reproduction pattern (consistent across multiple sessions/projects)
- Start Claude Code on laptop (VSCode integrated terminal, Windows 11)
- Leave the laptop at home, commute to a meeting / cafe / etc.
- Open claude.ai/code on mobile browser, connect Remote Control to the running session
- Send a message — works fine. Claude responds, runs tools (Bash, MCP, Write, Edit), completes
- Send another message — works fine
- After 2-4 successful exchanges, during what appears to be a routine turn, the session becomes unresponsive
- The mobile client continues to accept text input and send messages, but none of them advance the CLI. No new responses, no tool calls, no errors. Messages appear to queue silently.
- Attempting
/clear, sending random text, reconnecting the Remote Control tab, refreshing the browser — none of these wake the session - Hours later, upon returning home, I press
Esconce in the local terminal → the session immediately resumes, processes the queued messages, and works normally again
Evidence the session is not truly hung
- The CLI process stays alive and in a readable/writable state (proven by the fact that
Esclocally revives it instantly) - No API errors are logged in the
.jsonlsession file during the frozen period - When I inspected the
.jsonlafter recovery, the last entry before the freeze was a successfultool_usecompletion — there was no sign of streaming stall or network failure - This is not #25979 (API streaming stall) because that requires
kill -9to recover, while my case is fixed by a single local keystroke
Hypothesis
The CLI input-handling loop appears to enter a state where it is waiting for a local TTY keystroke (possibly as a confirmation, prompt, or UI state flag) that Remote Control's input channel does not deliver. This would explain why local Esc instantly unsticks it while remote input does not.
A possible cause: whatever UI prompt/permission/spinner state the CLI enters after certain tool calls may require a synchronous keypress from the terminal's process.stdin raw mode, which the Remote Control bridge isn't wired to send.
What Should Happen?
- Remote Control input should be fully equivalent to local TTY input — any state that local
Esc/Entercan unstick should also be unstickable from mobile - At minimum, a visible "session frozen — local intervention required" indicator in the mobile UI so users aren't silently blocked
- Ideally, automatic detection of "messages queued but not being processed" with a remote unstick mechanism
Business impact
I'm a solo founder (GT Dev Solutions, Madrid). Remote Control is a critical productivity feature for me — it's meant to let me keep working on client projects, reviewing deploys, and resolving urgent bugs while away from my laptop. In practice, with this bug, I can only rely on Remote Control for very short interactions (<5 messages) before needing to physically return home.
Yesterday (2026-04-19) I lost several hours of work while two separate sessions were frozen in this exact state. Both recovered instantly when I got home and pressed Esc. This has happened repeatedly over the past weeks — it's not an isolated incident.
Error Messages/Logs
No errors. The JSONL session file simply stops receiving new entries after the freeze point.
Steps to Reproduce
- Windows 11, Claude Code 2.1.112+ in VSCode integrated terminal
- Start a session with any project and MCP servers loaded (I have 18 MCPs configured globally, but the bug occurs even without any MCP calls)
- Leave the laptop running, connect from mobile browser via claude.ai/code Remote Control
- Interact normally — the freeze occurs non-deterministically after 2-4 exchanges, usually after (but not only after) a tool call completes
- Any further mobile input has no effect until local keypress
Claude Model
Opus
Is this a regression?
Possibly — Remote Control is relatively new. I don't have a known-working Claude Code version for this specific feature since adoption was gradual.
Last Working Version
_No response_
Claude Code Version
2.1.112 (also occurred in 2.1.108 and earlier 2.1.x)
Platform
Anthropic API (Max plan)
Operating System
Windows 11 (laptop/CLI side) + Android browser (mobile side)
Terminal/Shell
VSCode integrated terminal (bash/git-bash on Windows)
Additional Information
- Happens consistently across projects (I have multiple parallel sessions for different clients)
- Does NOT correlate with any specific tool — happens after Bash, Write, Edit, MCP calls, or even plain text responses
- Does NOT correlate with rate limits (I'm on Max plan, and the freeze persists long after any rate window would reset)
- Browser refresh on mobile does not re-sync — the issue is on the CLI side, not the web client
- Related but distinct: #47127 (feature request for Cancel button), #28508 (AskUserQuestion mobile sync), #25979 (API streaming stall requiring
kill -9)
Workaround: none remotely. Must physically access the laptop to press a key.
15 Comments
Am also having this exact issue with the mobile app on android I've tried writing skills to prevent hangs but even with timeout and --kill-after=5 on every single command it still hangs and its only when remote control is active
I keep running into this or a similar issue. Whenever a tool or subprocess gets stuck for any reason, the entire session becomes blocked with no way to rescue it remotely. This is a massive blocker for effective use of remote-control.
I am also experiencing this issue, with increasing frequency. This morning, after it happened, I restarted the machine and restarted code with remote, and it froze again after only 15 min. I have noticed that the app has a bug, where on screen rotate or screen on/off, it will clear pop-ups on the android side (usually waiting for input), and I wonder if this is the cause.
Experiencing this issue as well
Workaround validated today: Telegram plugin as an alternate input channel that bypasses the freeze
Reporting back with a concrete workaround that confirms the underlying hypothesis (Remote Control's input bridge is not equivalent to local TTY) and gives users an interim recovery mechanism without physical access to the laptop. This does not fix the bug — the freeze still happens — but it provides a "remote Esc" via a different code path.
Setup
Add the official Telegram plugin to the same Claude Code session you use for Remote Control:
(Setup details in the plugin docs; I documented zombie-process gotchas in #36964.)
Why it bypasses the freeze
The Telegram plugin delivers user messages into the session via a different ingress than Remote Control. From what I observed today:
user-prompt-submit-hookevents directly into the session's event loop — same code path local TTY input ultimately reaches.Escdoes: the queued Remote Control messages flush, the session resumes, and subsequent Remote Control input works again until the next freeze.Test today (2026-04-29)
After 4 paired pings over a 36-min window (one of them after a 15-min idle gap), the Telegram channel stayed live and responsive while the same Claude process was also serving Remote Control. The freeze pattern I described in the issue did not manifest during the Telegram test — but more importantly, when freezes have happened in the past (without the plugin loaded), I had no way to recover remotely; with the plugin loaded, a single Telegram message from my phone would have given me the same recovery effect as local
Esc.Why this is a workaround, not a fix
The root cause described in this issue is unchanged:
getUpdateslimitation), and introduces a token to manage.What this tells us about the underlying bug
The fact that any alternate input channel (Telegram plugin → MCP user-prompt-hook) unsticks the session reinforces the hypothesis from the original report: Remote Control's input is being dropped or queued behind a state machine that local TTY input bypasses. The freeze is not a process hang — it's an input-routing bug specific to the RC adapter.
This narrows the fix target: the RC input path needs to be verified equivalent to
process.stdinraw mode in all the states where the CLI's input handler may be waiting (permission prompts, post-tool spinners, AskUserQuestion, etc.). Whatever's blocking RC input but not TTY/plugin input is the bug.Recommendation
Until a real fix lands, document this as an interim workaround in the Remote Control docs:
Happy to provide more reproduction data or test instrumented builds if useful.
Reproducible trigger: running
/compactfrom the remote (mobile) clientI'm hitting what looks like the same bug, and I found a consistent trigger for it: sending
/compactfrom the remote client.Environment
Reproduction
/remote-control, then send/compactfrom the remote (mobile) clientCompactedis displayed× test(looks like a send failure), no response from the agentSo the queued remote input is flushed the moment I do anything locally. Local input always works; only the remote path freezes. This matches the "blocking on a local TTY keystroke" hypothesis in the original report — the remote messages seem to be queued but not delivered until a local stdin event wakes the loop.
What I ruled out (A/B testing, restart + reproduce each time)
"hooks": {}) → still freezessettings.json→ still freezesSo it's independent of hooks, permissions, MCP servers, and the rest of
settings.json. It really does look like the input-loop / TTY issue rather than anything in user config. PressingEsclocally (as others reported) and any other local input both serve as the "unstick" event here.The
/compactrepro is useful because it separates this from a generic “tool is slow” or API streaming stall. If local input immediately flushes queued remote input, then the live process is still healthy; the broken part is that the Remote Control input path is not waking the same TTY/input loop that local stdin wakes.A good diagnostic split would be:
/compact.If that wakes it, it strongly supports “Remote Control adapter/queue is not equivalent to local TTY input.” If it does not wake it, then the issue is deeper than just the RC input adapter.
This is also the class of problem I’ve been designing Faryo around: https://github.com/Snailflyer/faryo
Faryo is not a fix for this Claude Remote Control bug. It keeps Claude Code/Codex/shell inside the same
tmuxsession and gives phone/desktop browsers a separate lightweight workbench for output review, short input, approve/interrupt, and handoff. So it may be useful as an A/B comparison or escape-hatch style control surface when the official Remote Control path queues input but the underlying tmux-backed process is still alive.The important product requirement for the official fix is still exactly what this issue says: any state that local
Esc, local text input, or another local TTY event can recover should have a remote-visible state and a remote recovery action. Silent queuing is the worst failure mode because the phone makes the user think the session is still reachable when the host-side input loop is actually waiting elsewhere.Reporting a fresh occurrence + workaround stack — opened #61735 today which the duplicate-bot correctly flagged here. Adding 👍.
Variant: my case wasn't Remote Control specific — it was a pure
ScheduleWakeup(dynamic/loopmode) silent death. Session terminated for unknown reason (cluster recycle / OOM / crash, no on-disk forensics). All pending wakeups died with the process because the queue is in-memory only.Cost: Max plan subscription cancelled because of this single failure mode after a 3-day silent gap during a vacation (zdravim z plaze pings into the void).
Workaround stack shipped same-day, sharing in case it helps others:
/claudeslists running claude sessions with PID + pts + age + CPU,/interrupt Nsendsos.kill(pid, SIGINT)to the N-th session. TIOCSTI is kernel-blocked on modern Linux (sysctl dev.tty.legacy_tiocsti=0) so we can't inject Esc keystroke directly, but SIGINT to PID is the equivalent of Ctrl+C in the TTY — Claude Code reads it and breaks out of current operation. Self-protection refuses to signal the bot's own PID.~/.claude/scheduled_tasks.jsonon each call, re-attach on session resume (similar to how CronCreate already persists).@GustavoVzla validated a similar Telegram-as-alternate-input bridge above — same pattern. The two together (watchdog + remote-interrupt) get back ~95% of recovery capability without needing physical access.
— @honzastim
Quick follow-up: for me this turned out to be intermittent. Three phases since my report:
So it's not 100% reproducible, but the bug is still present — and when it happens, only local input recovers it.
By the way, I made a workaround skill to avoid the issue with a kicking alerm by monitor+sleep before the compaction. https://github.com/koteitan/my-skills/tree/main/skills/compact-unfreeze
+1 — Android (Claude Code app). Same input-hang pattern: after a few exchanges the session stops advancing remotely, every subsequent message from the phone just sits queued, and I have to physically return to the host machine and tap the terminal before it flushes and resumes. No visible tool in progress, no error in the mobile UI. The "Telegram-as-alternate-input bridge" workaround in the thread matches my observation that any local input wakes the session — RC input is the only path that doesn't.
Adding a matching data point from a different setup (also lines up with #47678 / #53328 / #54076):
Environment
claude --remote-controlinside a persistent tmux session.Repro
claude --remote-controlin tmux; connect from the mobile app.⚒ Channeling (Nh Nm)spinner indefinitely (observed counter climbing into the hours).[Tool result missing due to internal error].Notes
[Tool result missing due to internal error]+ "operation already succeeded, recovers only on local Esc" matches #53328's streaming-receive-race description specifically.Happy to provide more detail or logs if useful.
Confirming this is still present in v2.1.158 (latest as of 2026-05-31), and adding a data point that extends the report.
Environment: Linux aarch64 (NVIDIA DGX Spark / GB10), Claude Code 2.1.158, driving a long-running agent session over Remote Control.
Symptom: mid-turn the session hangs ("combobulating" / no UI progress); input typed on the remote side is queued but not processed while the turn appears stuck. Happens most often during turns that run several back-to-back tool calls.
Recovery — the key addition: local
Ctrl+C/Escusually unsticks the queued input, but not always — in a meaningful fraction of cases the local interrupt does nothing and the only options are to wait it out or kill the terminal. So the current "only local Esc recovers it" assumption is optimistic: sometimes even local Esc does not recover.Frequency: ~10 occurrences in a single multi-hour session — high enough to seriously disrupt remote-driven work.
Repro is just: drive a non-trivial agent task (multiple tool calls per turn) via Remote Control and watch for mid-turn stalls where remote input stops being consumed. A remote-side "unstick"/cancel signal (cf. #47127) would help, but the deeper bug is that the input queue stalls at all, and that local interrupt is not a reliable recovery.
Adding a clean-environment reproduction with a clear upstream/downstream split, in case it helps narrow this down.
Environment: Windows 11, Claude Code 2.1.183 (autoUpdatesChannel: stable)
Downstream (display) fully alive, upstream (control) dead:
The
Escworkaround from this issue does NOT recover it in my case.Everything else ruled out:
/logintoken refresh — no effect/remote-controlre-toggle + fully reopening the app — no effectclaude.exeprocess, no residual/orphan sessions — still repros (so it's not stale-session contention)claude doctorreports Remote Control ✔ (network/token are clean)/remote-control(.../session_<id>) matches the running session ID, so it is not routing to a dead session.Closed issues #37357 / #52084 / #52796 describe the same family of symptoms; reopening or linking may be warranted.
Adding corroborating data: 4 occurrences in one day across a multi-session tmux fleet (macOS, Claude Code 2.1.207, all sessions driven via tmux,
/remote-controlconnected from mobile). Same signature as OP: process alive, transcript (<sid>.jsonl) goes completely silent, composer holds unsent text, all local keystrokes are no-ops (Enter/Ctrl-C/Ctrl-U/Esc/printable chars — note: unlike OP, Esc does not revive for us). tmux is exonerated:pane_in_mode=0, other panes fine, pasted text still renders in the composer.Timing pattern (4/4, unusually consistent):
| # | last jsonl record (local time) | background subagent completes (SubagentStop) | stuck until |
|---|---|---|---|
| 1 | 08:42:48 | +5 s | manual restart |
| 2 | 13:33:35 | +7 s | restart at 13:44:54 |
| 3 | 11:14:02 | +5 s | restart ~2.5 h later |
| 4 | 14:03:26 | +7 s | restart 36 min later |
Three hard commonalities in all four:
/remote-controlwas active in every case (footer/rc). Zero wedges ever observed in sessions without /rc; the wedge class appeared the same day /rc was first used in the fleet.Additional observation (incident 3): while input was dead, new permission dialogs from still-running background agents kept rendering on screen (two different dialogs, ~11 min and ~2 h into the wedge) — rendering and the agent side stay alive; only local input handling is dead. The dialogs were unanswerable locally.
Recovery that works every time:
kill -TERM <claude-pid>+claude --resume <session-id>— session comes back healthy with full context.Repro attempts without a real remote client attached (headless /rc enabled, 6 dispatch cycles + 2 background-agent scenarios) did not trigger it, so a live remote-client/network event on the /rc channel seems to be a required ingredient.
Hypothesis based on the above: input-ownership handoff between the /rc bridge and the local TTY desyncs in a race window around turn-end when a SubagentStop lands 5–7 s later — local input loop loses ownership permanently while rendering continues.