Repository navigation
Remote Control unusable from mobile when host has many unarchived threads: thread/list scales with thread count and exceeds the mobile client's ~30s timeout #45246
Description
What version of the Codex App are you using (From "About Codex" dialog)?
- Windows Store package:
OpenAI.Codex 26.908.4834.0 - Bundled app-server:
codex-cli 0.154.0-alpha.6.2 - Mobile client: ChatGPT for Android (server logs report
client_name="codex_chatgpt_android_remote",client_version="dev")
What subscription do you have?
ChatGPT Pro
What platform is your computer?
Windows 11 Pro 10.0.26200 x64, NVMe SSD. Native Windows host (no WSL).
What issue are you seeing?
Connecting to the desktop host from the ChatGPT mobile app fails most of the time and only occasionally succeeds. Restarting both apps sometimes "fixes" it, but only by coincidence.
The host-side relay websocket is healthy the whole time (wss://chatgpt.com/backend-api/wham/remote/control/server stays Connected for hours). What fails is the first request the phone sends after initialize: thread/list takes 20-42 seconds on the host, and the mobile client gives up at ~30 s. Whether a given connection attempt succeeds is essentially a coin flip on whether that one call lands under 30 s.
The variable is the number of unarchived threads in state_5.sqlite. I measured thread/list (default params, as sent by the phone) against the same 0.154 app-server at three thread counts on the same machine, same session:
| Unarchived threads | thread/list latency |
Mobile result |
|---|---|---|
| 8,361 | 20-42 s (5 samples from phone requests, median 30 s) | fails most attempts |
| 998 | 3.3-3.5 s | works |
| 183 | 1.7-1.9 s | works |
The only change between rows was bulk-archiving threads (setting archived=1 and moving the rollout to archived_sessions/). No app restart, no config change.
Of the 8,361 threads, ~5,000 had source='exec' and ~2,300 were thread_source='subagent', i.e. produced by codex exec automation and spawned subagents. Anyone running orchestration pipelines will accumulate thousands of these quickly (this profile gains ~150/day), so the host degrades toward "mobile can't connect" within a couple of weeks even though the desktop app itself still feels fine.
Evidence from logs_2.sqlite
Phone request/response timing (same connection, thread/list request id 339 and 341):
15:32:14 message_processor app-server request: thread/list connection_id=ConnectionId(41) request_id=Integer(339)
15:32:43 recorder app_server.request{... rpc.method="thread/list" ... app_server.client_name="codex_chatgpt_android_remote"}: Resuming rollout from ".../rollout-...jsonl"
15:32:44 recorder ...: Resumed rollout with 31155 items
15:32:51 message_processor app-server request: thread/list connection_id=ConnectionId(42) request_id=Integer(341)
15:33:22 recorder ...: Resuming rollout from ...
15:33:23 recorder ...: Resumed rollout with 31155 items
Note that ~29 s elapse before the rollout parse starts, so the cost is in the list/scan over the thread set, not (primarily) in parsing one big rollout.
When the phone retries, the host shows the per-device connection being closed on a 30 s cadence:
17:12:15 client_tracker forwarding remote control connection closed transport event connection_id=ConnectionId(25)
17:12:45 client_tracker forwarding remote control connection closed transport event connection_id=ConnectionId(26)
17:12:45 client_tracker forwarding remote control connection closed transport event connection_id=ConnectionId(27)
17:13:45 client_tracker forwarding remote control connection closed transport event connection_id=ConnectionId(1)
17:14:15 client_tracker forwarding remote control connection closed transport event connection_id=ConnectionId(28)
17:14:45 client_tracker forwarding remote control connection closed transport event connection_id=ConnectionId(30)
17:15:15 client_tracker forwarding remote control connection closed transport event connection_id=ConnectionId(31)
17:15:45 client_tracker forwarding remote control connection closed transport event connection_id=ConnectionId(32)
Meanwhile the host's own relay socket never dropped:
remote control websocket status changed previous_status=Connecting next_status=Connected
connected to app-server remote control websocket ... subscribe_cursor_present=true
What steps can reproduce the bug?
- On a Windows host with Codex Desktop and Remote Control enabled, accumulate several thousand unarchived threads (e.g. run
codex execin a loop, or any workflow that spawns many subagents;state_5.sqlitethreadstable witharchived=0). - From the ChatGPT mobile app, open Remote and select the host.
- Observe the phone sits on connecting, then fails with the generic "couldn't connect to desktop" error. Host logs show
initialize+thread/listarriving, then the client connection closed ~30 s later beforethread/listreturned. - Archive most threads (any method), retry: connection succeeds immediately.
A quick way to measure without a phone: run codex app-server over stdio, send initialize then thread/list with {} params, and time the response. At 8k unarchived threads it takes tens of seconds on a fast NVMe machine.
What is the expected behavior?
thread/listfor the mobile client should be bounded (index-only, paginated, no rollout scans) regardless of how many threads exist. A phone needs the ~20 most recent, not a scan of 8,000.- The mobile client should surface "host is slow to list threads" rather than "couldn't connect to desktop", since the host is connected; the generic error sends users down the wrong troubleshooting path (re-pairing, restarting, checking sleep/network).
- Threads produced by
codex execand subagent spawns should probably not count toward the interactive list at all, or should auto-archive when their parent finishes. Today they pile up invisibly and there's no bulk-archive affordance in the app.
Additional information
- Related: Remote Control App Sessions Broken on Android App when using Ubuntu WSL2 on Windows #43565 (Android, WSL2 host,
thread/list46.6 s with ~920 threads / 40 GB of rollouts), app-server loads ALL session files on every thread/list call — causes high CPU, slow startup, and background token waste #22411 (thread/listloads all session files), Windows Desktop: many threads in one project make sending and responses very slow even on fast model #24427 (Desktop slow with many threads in one project), Windows + Android Remote Control enters reconnect loop after successful initialize/thread-list #39954 (Windows/Android reconnect loop afterinitialize/thread/list). This report isolates the unarchived-thread count as the controlling variable with before/after measurements on a native Windows host. - Workaround that fixed it for me: archive everything with no activity in N days (
archived=1,archived_at, move rollout toarchived_sessions/), run nightly. Pinned/sectioned threads and long-running goals are untouched because the filter usesrecency_at_ms, notcreated_at_ms. - The
logs_2.sqliteon this host had also grown to 3.4 GB with 91% free pages (~128k live rows); a manualVACUUMbrought it to 0.26 GB. Probably not the cause here, but the app never compacts it. - Account IDs, installation/server/environment IDs, thread IDs, paths, and conversation content have been omitted.
Activity
spike: raise the fuse above what the call actually costs
codex: Codex workers on the bus, and the conjoin registry-sync fix (#55…