Remote control can get stuck after idle or network changes with 409 Conflict until re-enrollment

Resolved 💬 3 comments Opened May 22, 2026 by agustinustheo Closed May 22, 2026
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What version of the Codex App are you using?

Originally observed on host Codex App 26.519.31651 (bundle 3017) on 2026-05-22.

Still present after host-side recovery and retest on the same installed desktop build on 2026-05-22.

Current bundled/local CLI observed on the host:

  • Bundled app CLI: codex-cli 0.133.0-alpha.1
  • PATH CLI: codex-cli 0.133.0

Authoritative release check on 2026-05-22:

  • Latest stable openai/codex GitHub release: rust-v0.133.0, published 2026-05-21
  • Newest visible alpha release in GitHub releases: rust-v0.133.0-alpha.4, published 2026-05-21

This report does not claim every desktop/mobile combination was tested. It claims the failure still reproduced on the currently installed macOS host app after updating earlier the same day.

What subscription do you have?

ChatGPT Pro ($100 tier).

What platform is your computer?

Host: MacBook Pro, Apple Silicon, macOS 15.6.1 (24G90), arm64

Mobile: ChatGPT iOS remote-control surface on iPhone. Exact iOS version was not captured during the host-side investigation, but screenshots were taken on 2026-05-22 while the issue was reproducing.

What issue are you seeing?

ChatGPT iOS Remote Control is not acting like a stable live control surface for the connected macOS Codex host.

The host can be online and usable locally, but iOS and the remote-control backend can drift into stale or contradictory state:

  • Remote control can work initially from iPhone.
  • After about 15-20 minutes, or after entering a new network / switching connectivity, the iPhone can show the host as stuck connecting, offline, or requiring reconnect.
  • The host can still have Codex running locally at the same time, so the machine is not simply powered off.
  • Restarting the Codex app, restarting the Codex server, or disconnecting/reconnecting from the phone can sometimes temporarily recover it.
  • The failure can persist even though local Codex is still running and reachable.

This is not a basic Wi-Fi outage. The more specific failure is that the host and the remote-control service appear to disagree about whether the same remote-control session is still online.

When the failure is active, the host-side CLI can report:

Error: Remote control is enabled on Host-MacBook-Pro.local but the connection is errored.

And the remote-control websocket can repeatedly return:

HTTP error: 409 Conflict
body: {"detail":"Remote app server already online"}

The persisted remote-control enrollment being reused during failure was a headless row with an empty app_server_client_name:

rowid=1
app_server_client_name=''
server_id=srv_e_6a0ff555af9c832782b7572b744d66cc
environment_id=env_e_6a0ff555af8c8327b22facdc75ac055a
server_name=Host-MacBook-Pro.local

Current corroboration

The local evidence supports a stale-session / stale-enrollment failure, not raw SQLite corruption:

  • ~/.codex/state_5.sqlite passed PRAGMA quick_check and PRAGMA integrity_check.
  • ~/.codex/logs_2.sqlite also passed integrity checks.
  • The failure was tied to stale logical remote-control state, not broken database pages.
  • During investigation, remote_control_enrollments initially contained multiple rows for the same account/websocket URL, including a stale older row and an active headless row with app_server_client_name=''.
  • At one point, codex remote-control stop printed success, but a long-lived codex remote-control process still existed and still held an established TLS connection to the remote-control backend.
  • Forcing a fresh enrollment immediately restored connectivity.

Representative host-side evidence:

2026-05-22 13:14:55 WARN codex_app_server_transport::transport::remote_control::websocket
failed to connect to app-server remote control websocket: wss://chatgpt.com/backend-api/wham/remote/control/server,
err: failed to connect app-server remote control websocket `wss://chatgpt.com/backend-api/wham/remote/control/server`:
HTTP error: 409 Conflict,
body: {"detail":"Remote app server already online"}
2026-05-22 13:19:02 INFO codex_app_server_transport::transport::remote_control::websocket
created new remote control enrollment: websocket_url=wss://chatgpt.com/backend-api/wham/remote/control/server,
account_id=<redacted>, server_id=srv_e_6a0ff555af9c832782b7572b744d66cc,
environment_id=env_e_6a0ff555af8c8327b22facdc75ac055a
2026-05-22 13:19:05 INFO codex_app_server_transport::transport::remote_control::websocket
connected to app-server remote control websocket: wss://chatgpt.com/backend-api/wham/remote/control/server

So the same host could be made healthy again immediately by forcing a fresh enrollment, which strongly suggests stale session / stale enrollment handling on reconnect rather than a basic reachability failure.

What steps can reproduce the bug?

  1. Start Codex Remote Control on macOS with codex remote-control start.
  2. Confirm that the iPhone can see and connect to the host.
  3. Use the remote connection normally, or leave it idle for around 15-20 minutes.
  4. Change networks, or let the machine experience a connectivity transition such as Wi-Fi changes, hotspot changes, or moving between networks.
  5. Return to the iPhone remote-control surface.
  6. Observe the host stuck connecting, marked offline, or showing Reconnect.
  7. On the host, try codex remote-control start again.
  8. Observe Remote control is enabled on ... but the connection is errored.
  9. Inspect logs and observe repeated 409 Conflict responses with {"detail":"Remote app server already online"}.

Host-side recovery that worked locally:

  1. Stop remote control.
  2. Ensure the ghost codex remote-control process is actually gone.
  3. Clear persisted stale enrollment rows from ~/.codex/state_5.sqlite.
  4. Start remote control again.
  5. Observe a fresh enrollment being created and the websocket connecting successfully.

What is the expected behavior?

  • If a network transition interrupts the old remote-control session, Codex should either reconnect automatically or invalidate the stale session transparently.
  • codex remote-control stop should not report success while a ghost remote-control session is still effectively online from the server's point of view.
  • A stale headless enrollment should not leave the host stuck in a persistent connection is errored / 409 Conflict state that requires local SQLite cleanup.
  • The mobile surface should converge back to the real host state instead of remaining stuck in connecting/offline limbo.

Related issues checked

Same defect family / supports amending an existing upstream issue:

  • openai/codex#23470: remote-control can get stuck after macOS sleep with 409 Conflict until enrollment is manually reset

Related but broader remote-control state issues:

  • openai/codex#22773: iOS/macOS Remote Control broken after desktop update: host online, mobile 403/offline/stale Plan state
  • openai/codex#23915: Codex App Remote Control setup authenticates but shows no devices

The split is important: this report is focused on stale online/offline state after idle or network transitions, with concrete 409 Conflict evidence and successful recovery through re-enrollment.

Additional information

Official docs checked against the intended feature behavior:

The docs describe ChatGPT mobile as a supported Remote Control surface for starting, steering, approving, reviewing, and reconnecting to Codex work on a macOS host. I understand the feature is still a preview. Preview status does not make stale session recovery optional.

This report is narrower and updated for current versions:

  • reproduced on Codex App 26.519.31651
  • reproduced with current 0.133.0 / 0.133.0-alpha.1 host tooling
  • triggered not only by sleep/wake suspicion, but also by ordinary network transitions and mid-session idle/reconnect behavior

Sanitized screenshots from the 2026-05-22 reproduction. Hostnames and personal names are redacted.

Main iOS screen stuck loading:

<img width="1170" height="2532" alt="Sanitized iOS main screen showing the host stuck connecting" src="https://github.com/user-attachments/assets/cc46c397-fde3-4a25-bba7-377bca6ca16f" />

Connections sheet showing stale/offline state:

<img width="1170" height="2532" alt="Sanitized iOS connections sheet showing the affected host marked offline" src="https://github.com/user-attachments/assets/57f7775f-9609-4161-85c0-6d073fd36699" />

Offline/reconnect state on iOS:

<img width="739" height="1600" alt="Sanitized iOS screen showing the host offline with reconnect" src="https://github.com/user-attachments/assets/e36432ac-7f05-4222-8f21-abba58671872" />

Host-side terminal showing the errored remote-control session:

<img width="1496" height="540" alt="Sanitized terminal screenshot showing remote control enabled but connection errored" src="https://github.com/user-attachments/assets/2548a8d0-97f5-4482-b890-d16e5b34fbe2" />

Temporary Fix (For debugging and highlighting the error, use at your own risk)

Adding the current user-side workaround here in case it helps others unblock themselves while the underlying reconnect/state bug is investigated.

Workaround repo and installer:

What this workaround does:

  • installs a codex-remote helper wrapper and a codex-remote-ensure helper under ~/.local/bin
  • bootstraps and re-enables Codex app-server remote control
  • installs a LaunchAgent that re-runs the ensure helper every 60 seconds
  • provides a soft recovery path for the connection is errored / 409 Conflict state
  • escalates to backing up and clearing remote_control_enrollments from ~/.codex/state_5.sqlite when the stale remote session does not drain on its own

Relevant files:

This is not meant to claim the bug is fixed. It is a defensive local workaround that made the affected host recover more reliably after the stale online/offline state showed up.

View original on GitHub ↗

3 Comments

github-actions[bot] contributor · 3 months ago

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

  • #23470

Powered by Codex Action

agustinustheo · 3 months ago

I think this is a duplicate issue, closing it, but I think this info is helpful for debugging.

jshaofa-ui · 3 months ago

Proposed Solution: Remote Control 409 Conflict — Stale Enrollment Recovery

Root Cause

When a network transition or idle period interrupts the remote-control WebSocket:

  1. Old WebSocket silently broken (no proper disconnect handshake)
  2. Server-side still considers old session "online"
  3. codex remote-control stop reports success but ghost process still connected
  4. New connection gets 409 Conflict: Remote app server already online
  5. Stale enrollment with empty app_server_client_name blocks fresh enrollment

Fix

  1. Auto-Re-enrollment on 409: Detect 409 Conflict, kill ghost processes, clear stale enrollment, force fresh enrollment
  2. Proper Process Cleanup on Stop: Close WebSocket properly, verify process is gone, clear enrollment
  3. Stale Enrollment Detection: Auto-cleanup rows with empty app_server_client_name older than 5 minutes

Key Code Change

async fn handle_connect_conflict(&mut self) -> Result<()> {
    self.kill_stale_processes().await?;
    self.clear_stale_enrollments().await?;
    let enrollment = self.create_fresh_enrollment().await?;
    self.connect_with_enrollment(&enrollment).await
}

Full solution: solutions/codex-24024-remote-control-409-conflict-stale-enrollment-fix.md