Regression: macOS migration clones installation identity and Remote Control fails with 409

Open 💬 1 comment Opened Jul 31, 2026 by sinadarvi
💡 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?

ChatGPT desktop app with bundled Codex:

  • App version: 26.727.40816
  • Bundle build: 6067

What subscription do you have?

Not relevant to the failure; the same ChatGPT account was used on both Macs.

What platform is your computer?

  • Destination: Mac mini (Mac16,10), Apple Silicon (arm64)
  • macOS 26.6 (25G72)
  • Source: MacBook Pro
  • The destination Mac was migrated from the source Mac using macOS Migration Assistant / copied user data.

Real hostnames and all account, installation, environment, server, request, and key identifiers are intentionally redacted.

What issue are you seeing?

After migrating from a MacBook Pro to a Mac mini, enabling Settings > Connections > Control this Mac > Allow connections failed. The toggle returned to the off state and the desktop app showed:

Couldn't update remote control availability

The app server repeatedly attempted to connect to:

wss://chatgpt.com/backend-api/wham/remote/control/server

and received:

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

Only one ChatGPT desktop process and one bundled Codex app-server process were running locally when checked, so this was not caused by two active local app-server processes.

The source and destination Macs had inherited the same machine-scoped identity from:

~/.codex/installation_id

Historical local logs showed the same installation identity being used first by the source Mac and later by the destination Mac, despite different hostnames. The backend therefore treated the two physical Macs as the same Remote host.

Signing out was not a recovery mechanism: signing out affected both devices, and signing back in did not regenerate the local installation identity. A normal app reinstall would also be expected to preserve ~/.codex, so it does not provide an obvious fresh-device path. Existing projects still appeared after sign-in because the local project/thread state was preserved; this is expected but makes it less clear to a user that the machine identity was also preserved.

This appears to be a regression or still-unhandled case of #22950 on a substantially newer app build. It is also related to the stale-enrollment 409 Conflict behavior in #24024, but the trigger here was machine migration and a cloned installation_id, not idle time or a network transition.

What steps can reproduce the bug?

  1. Install and use ChatGPT/Codex on a source Mac with Remote Control enrolled.
  2. Migrate the source Mac's user account/data to a second Mac using macOS Migration Assistant or another mechanism that copies ~/.codex.
  3. Keep or later run ChatGPT/Codex on both physical Macs under the same ChatGPT account.
  4. On the migrated destination Mac, open Settings > Connections > Control this Mac.
  5. Enable Allow connections.
  6. Observe the generic Couldn't update remote control availability toast.
  7. Inspect ~/.codex/logs_2.sqlite and observe repeated 409 Conflict responses with {"detail":"Remote app server already online"}.
  8. Compare ~/.codex/installation_id on both physical Macs and observe that Migration Assistant cloned the machine-scoped identity.

Workaround that resolved the issue

The recovery was performed only on the migrated destination Mac.

  1. Fully quit ChatGPT/Codex and related Remote/app-server processes on both Macs.
  2. Back up the relevant local files:
~/.codex/installation_id
~/.codex/.codex-global-state.json
~/.codex/state_5.sqlite
  1. Move aside the migrated identity:
mv ~/.codex/installation_id <backup-location>/installation_id.migrated
  1. Clear only the persisted Remote Control enrollment rows, preserving the rest of the thread/project database:
sqlite3 ~/.codex/state_5.sqlite "DELETE FROM remote_control_enrollments;"
  1. Remove the mirrored local Remote host identity keys from ~/.codex/.codex-global-state.json:
electron-local-remote-control-installation-id
electron-local-remote-control-environment-id

The client/controller enrollment keys were not intentionally removed.

  1. Restart ChatGPT/Codex on the destination Mac.
  2. The app generated a different ~/.codex/installation_id, created one fresh Remote enrollment row, and the global-state installation ID matched the new file.
  3. Enable Allow connections again.
  4. The next observed Remote websocket result was connected; the repeated 409 loop stopped.

The workaround preserved local projects, chats/threads, plugins, and general Codex configuration.

What is the expected behavior?

  • A machine-scoped installation identity should not be silently cloned onto different physical hardware during Migration Assistant restore.
  • On startup, Codex should detect that a persisted installation identity is running on materially different hardware and either regenerate it or prompt the user.
  • Receiving 409 Conflict: Remote app server already online for a migrated/cloned identity should trigger a safe re-enrollment flow instead of indefinite retries and a generic availability toast.
  • Settings should provide a supported Repair Remote Control or Reset this device identity action.
  • Signing out or reinstalling should clearly explain whether local device enrollment is preserved.
  • Recovery should not require manually editing JSON or SQLite.
  • The error shown in Settings should distinguish duplicate device identity from network, authentication, workspace-policy, or permission failures.

Related issues

  • #22950 — same Migration Assistant / duplicated ~/.codex/installation_id root cause; closed as completed on an older build
  • #24024 — related persistent 409 Conflict / stale enrollment family; different trigger

Additional confirmation after recovery

  • The destination Mac's regenerated installation identity differs from the migrated identity.
  • The global-state mirror matches the new identity.
  • Exactly one fresh Remote enrollment row exists.
  • The latest Remote Control websocket event is a successful connection.

This report intentionally omits raw identifiers and credentials. Sanitized logs with timestamps or request IDs can be provided privately if maintainers need them.

View original on GitHub ↗

1 Comment

github-actions[bot] contributor · 28 days ago

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

  • #35774

Powered by Codex Action