iOS remote client times out loading long desktop Codex sessions and has no retry path

Open 💬 2 comments Opened Jun 16, 2026 by linerking
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

Summary

When using the iOS client to remotely control/access Codex Desktop, long-running sessions are prone to timing out while loading messages/session state. After the timeout, the iOS UI does not appear to retry automatically, and there is no clear manual retry path.

The visible error in the iOS UI is localized Chinese:

加载消息时出错:Codex 请求超时。

Roughly: "Error loading messages: Codex request timed out."

Environment

  • Remote client: iOS Codex/ChatGPT remote-control flow
  • Host: Codex Desktop
  • Date observed: 2026-06-16
  • Exact iOS/Desktop versions: not captured yet

Reproduction

  1. Start or continue a Codex Desktop session.
  2. Let the session become long enough that the thread/history contains a substantial amount of content.
  3. Open the same session from iOS through the remote-control flow.
  4. Attempt to load/resume/pull the long session messages.

Expected behavior

The iOS client should recover long sessions reliably. If a request times out, it should either:

  • retry automatically with backoff,
  • load messages incrementally/paginated instead of requiring one large fetch,
  • resume from the last successfully fetched point, or
  • show a clear manual retry action.

Actual behavior

For long sessions, the iOS client frequently times out while loading messages/session state. After the timeout, the UI displays:

加载消息时出错:Codex 请求超时。

There does not appear to be an automatic retry mechanism or an obvious retry button, so transient network/server delays become a hard failure from the user's point of view.

Impact

Long-running Codex Desktop sessions become unreliable from iOS, especially over mobile or weaker networks. This makes it difficult to monitor or resume active desktop work remotely once the conversation history grows large.

Suggested direction

This would be more robust with incremental/paginated message loading, request retry/backoff for timeout failures, and a visible retry action in the timeout state.

View original on GitHub ↗

2 Comments

github-actions[bot] contributor · 2 months ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #28346
  • #28340

Powered by Codex Action

iamluheng · 14 days ago

Sanitized reproduction with app-server evidence

I reproduced this on an Apple Silicon macOS host with two active long-running threads. This comment intentionally omits task IDs/titles, workspace paths, repository names, source code, commands, commit hashes, network addresses, account identifiers, and conversation content.

Environment

  • Host: macOS 26.5.1, arm64
  • Codex Desktop: 26.727.51351
  • Bundled Codex/app-server recorded by the affected threads: 0.146.0-alpha.9.2
  • iOS Remote client recorded by app-server: 1.2026.209
  • Observed: 2026-08-14

Sanitized thread sizes

  • Selected thread A: about 107.6 MB / 40.3k persisted items
  • Selected thread B: about 718.7 MB / 312.3k persisted items
  • Two other already-loaded desktop threads: about 417.8 MB / 121.2k items and 291.9 MB / 135.0k items

Both selected threads were alive and producing new events.

What happens on each iOS Remote connection

The app-server logs show that a single mobile connection does not fetch only the selected thread's recent visible messages. Instead it repeatedly:

  1. resumes another already-loaded desktop thread from its complete rollout;
  2. runs thread/turns/list for selected thread A from the beginning;
  3. runs thread/turns/list for another unrelated loaded thread from the beginning;
  4. runs thread/turns/list for selected thread B twice concurrently.

One connection therefore parses approximately 2.10 GiB of rollout history. The 718.7 MB thread takes about 3.0-3.1 seconds per full scan, and the duplicate requests overlap.

Across six consecutive connections, the same pattern repeated. The client disconnected roughly four seconds after the history requests began; the host then logged:

dropping message for disconnected connection

The client reconnected and restarted the same full-history work, producing a retry/load storm.

Integrity and resource checks

  • Every rollout replay reported parse errors: 0.
  • The state database integrity check returned ok.
  • No database lock or missing rollout was observed.
  • The host had ample free memory and disk with no swap pressure.
  • During repeated replay, app-server CPU briefly exceeded three cores and RSS grew above 3 GiB.

This appears to be an eager hydration/fan-out problem rather than corrupt state or insufficient host resources.

Expected protocol/UI behavior

On remote connection or thread selection, return only:

  • thread metadata and active-turn status;
  • a bounded recent tail, preferably the newest 50-100 visible user/assistant text messages, subject to a small byte cap;
  • a cursor for older visible messages;
  • live events after the snapshot cursor.

The initial response should exclude old tool outputs, hidden reasoning/event records, images/blobs, and unrelated loaded threads. Older text should load lazily when scrolling. Heavy tool output should require a separate explicit fetch.

Additionally:

  • deduplicate concurrent thread/turns/list calls for the same thread;
  • do not hydrate every desktop-loaded thread when mobile connects;
  • do not block selected-thread rendering or the composer behind unrelated history;
  • enforce server-side item/byte caps so a client omission cannot trigger an unbounded response;
  • allow a timed-out client to resume from its last cursor instead of restarting from byte zero.

This is consistent with the requested direction in #21211 and #25779, and complements the Android evidence in #38023. The iOS-specific additional finding here is the cross-thread fan-out plus duplicate full read of the largest thread on every connection.