Codex mobile shows macOS host offline/stuck when state_5.sqlite threads table is malformed
Summary
Codex mobile Remote Control stopped working for a macOS Codex Desktop host that had worked the previous day. ChatGPT iOS showed the macOS host as offline / last seen hours ago, and later showed the same host with a spinner and loading placeholders. The macOS host was online, Codex Desktop was running, firewall was disabled, and the desktop app was up to date.
Local investigation found ~/.codex/state_5.sqlite is corrupt, specifically the threads table/indexes. Desktop logs repeatedly report sqlite state db unavailable while trying to update thread metadata. This appears to make mobile Remote Control surface a stale/offline/loading state instead of detecting local state DB corruption and showing a repairable error.
Environment
- Codex Desktop:
26.513.31313/ bundle2867 - Bundled CLI:
codex-cli 0.131.0-alpha.9 - Host OS: macOS
26.3.1 (a)build25D771280a - Host arch:
arm64 - Mobile: ChatGPT iOS Codex Remote Control
- Host identity/IDs intentionally redacted
What happened
- Codex mobile Remote Control worked normally the previous day.
- The next day, ChatGPT iOS showed the macOS host as offline / last seen hours ago.
- Tapping reconnect did not restore it.
- Reopening the mobile surface later showed the host name with a spinner and loading placeholders.
- On the Mac, Codex Desktop was running and responsive.
- macOS firewall was disabled.
- The app bundle was current according to the appcast.
- Local remote-control enrollment still existed in
~/.codex/state_5.sqlite. lsofshowed the Codex app server had outbound HTTPS connections; this did not look like a LAN listener/firewall issue.- The failing local state DB was then checked directly with SQLite.
Diagnostics
sqlite3 ~/.codex/state_5.sqlite 'pragma integrity_check;' returns:
Error: stepping, database disk image is malformed (11)
*** in database main ***
Tree 5 page 147: btreeInitPage() returns error code 11
Tree 36 page 129: btreeInitPage() returns error code 11
Tree 35 page 131: btreeInitPage() returns error code 11
Tree 34 page 34: btreeInitPage() returns error code 11
Tree 33 page 33: btreeInitPage() returns error code 11
Tree 24 page 24: btreeInitPage() returns error code 11
Tree 23 page 23: btreeInitPage() returns error code 11
Tree 22 page 22: btreeInitPage() returns error code 11
Tree 21 page 21: btreeInitPage() returns error code 11
Tree 20 page 20: btreeInitPage() returns error code 11
wrong # of entries in index idx_threads_archived_cwd_updated_at_ms
wrong # of entries in index idx_threads_archived_cwd_created_at_ms
wrong # of entries in index idx_threads_updated_at_ms
wrong # of entries in index idx_threads_created_at_ms
wrong # of entries in index idx_threads_provider
wrong # of entries in index idx_threads_source
wrong # of entries in index idx_threads_archived
wrong # of entries in index idx_threads_updated_at
wrong # of entries in index idx_threads_created_at
wrong # of entries in index sqlite_autoindex_threads_1
The affected rootpages correspond to threads and its indexes.
Desktop logs contain repeated failures like this, with thread IDs redacted here:
2026-05-17T19:28:50Z error [electron-message-handler] Request failed ... error={"code":-32603,"message":"failed to update thread metadata: thread-store internal error: sqlite state db unavailable for thread <redacted>"} method=thread/metadata/update
2026-05-18T02:11:59Z error [electron-message-handler] Request failed ... error={"code":-32603,"message":"failed to update thread metadata: thread-store internal error: sqlite state db unavailable for thread <redacted>"} method=thread/metadata/update
A SQLite .recover against a snapshot of the DB completed successfully, and the recovered DB passes pragma integrity_check with ok. The recovered DB retained the remote_control_enrollments row. Recovery has not yet been applied to the live install at the time of filing.
Expected behavior
If Codex Desktop finds that state_5.sqlite is malformed or that threads is unavailable:
- Desktop should surface a clear local recovery/repair message instead of leaving mobile to show the host as offline or stuck loading.
- Mobile Remote Control should show a specific actionable error, for example that the desktop host is online but local state is corrupted/unavailable.
- Codex should preserve the malformed DB, rebuild/recover from session JSONL where possible, and re-index threads automatically or via a visible repair action.
- Remote-control host health should distinguish between transport/connectivity failure and local state-store failure.
Actual behavior
The phone shows the host as offline/stale or stuck loading, even though the desktop host is running. The local SQLite corruption is only discoverable by manually running pragma integrity_check and reading desktop logs.
Related issues
This looks related to both:
- #20493, which reports corrupt
state_5.sqlitecausing desktop chats to disappear/blank. - #22773, which tracks broader iOS/macOS Remote Control stale/offline/hydration failures.
This report is narrower: a malformed threads table/indexes in state_5.sqlite appears to make mobile Remote Control present the macOS host as offline/stuck rather than reporting a local state-store failure.
Privacy note
This report intentionally omits account IDs, server/environment IDs, raw hostnames, screenshots, full local paths outside ~/.codex, and thread IDs.
7 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Follow-up: after quitting Codex, backing up
~/.codex/state_5.sqlite*, recovering the SQLite DB with.recover, replacingstate_5.sqlite, and removing the old WAL/SHM files, mobile Remote Control started working again.Post-repair checks:
This confirms that the malformed
threadstable/indexes instate_5.sqlitewere at least sufficient to cause the observed mobile offline/stuck behavior.The follow-up confirming
.recoverfixed mobile Remote Control is useful because it separates transport health from local state-store health.For remote control, the host should probably publish a small health vector instead of one generic online/offline state:
In this case the host was online, but
threadswas not a reliable data source. Showing that as offline/stale on mobile sends the user toward network and pairing fixes, when the actionable fix is local state repair/reindex.A simple solution for anyone who encounters this issue in future: simply send this text to Codex and ask them to sort it out:
I ran into this issue too. Later I found that it was caused by a corrupted
state_5.sqlite, which madecodex app-serverfail to start. In the end, I also had to resetremote_controlso the app and client could reconnect properly and fully resolve the problem.ChatGPT App Could Not Connect to Codex Desktop: A Remote Control Fix Caused by a Corrupted
state_5.sqliteOne-Line AI Repair Prompt
This is the prompt I would give to Codex or Claude if I wanted it to repair the same problem end to end:
Background
I recently ran into a strange issue: the ChatGPT mobile app could not connect to Codex Desktop running on my Mac. The Mac side looked fine. Codex Desktop could open normally, and nothing obvious suggested that the local client was broken.
At first, I suspected the usual suspects: mobile network, account state, proxy settings, or some connection issue between the phone and the Mac.
Then I found a very relevant GitHub issue: openai/codex#23247. The discussion there mentioned a similar symptom: the ChatGPT iOS app showed the macOS host as offline or stuck loading, while the local
~/.codex/state_5.sqlitedatabase was malformed.That matched the direction of my own failure, so I stopped looking only at the mobile app and started tracing the local
codex remote-controlpath on the Mac.Symptoms
On the phone, the symptom was simple: ChatGPT App could not connect to my Mac. It looked as if Codex Desktop was offline.
On the Mac, I first checked the basic client state:
The local
codexcommand had already been switched to the standalone install:The real failure showed up when I ran:
It failed with:
At this point, it looked like a missing socket problem, or maybe the app-server simply did not start. But after checking the daemon state more closely, I found that the missing socket was only the visible symptom. The app-server process was exiting during startup.
Root Cause
The root cause was a corrupted
~/.codex/state_5.sqlitedatabase. Because of that,codex app-serverfailed while initializing the local state database, andremote-controlnever got far enough to create the control socket.The key diagnostic command was:
On my machine, it returned errors like:
I also tried starting the app-server manually with a temporary Unix socket:
That exposed the error more directly:
So I could basically rule out DNS, TCP 443 connectivity, TLS certificates, the mobile network, and the macOS firewall. The phone showed a connection failure, but the thing that was actually broken was the local Codex state database on the Mac.
How It Works
The misleading part is that the mobile app only shows the host as offline or unavailable. Locally,
codex remote-controlcomplains that a Unix socket does not exist. Both symptoms point away from the actual root cause.The real chain looks like this:
I tried to solve the same issue with gpt 5.5 medium and it found another root cause. I want to share it here so people can try.
My phone can connect to the destination mac, but my mac couldn't and it used to work.
Problem
Codex Desktop could discover another Mac, but starting a remote session failed. The stale device kept appearing, and discovery reused the same broken entry.
Logs showed: Remote-control client has been revoked
This was not the same root cause as issue #23247, because SQLite was healthy:
Expected:
Cause
Codex had a stale local remote-control client enrollment stored in:
The important key was:
Deleting it only from the main file was not enough, because Codex could restore it from memory or the .bak file.
Fix
Quit Codex Desktop first:
Back up the state files:
Remove the stale enrollment from both files:
Verify:
Expected:
Reopen Codex Desktop.
Result
Settings → Connections → Controlother devices should reset to the fresh setup flow. Click Set up, authorize on chatgpt.com, then discover/pair again.