Skip to content

Codex leaves valid rollout files unindexed in state DB and lacks supported reindex repair #31433

Open

Description

@atlantho

What version of Codex CLI is running?

codex-cli 0.142.5

What platform is your computer?

Windows 11 Pro, x64, OS build 10.0.26200, locale de-DE.

Codex is installed with the standalone Windows installer. The Windows Codex Desktop app is configured to run the agent in WSL:

[desktop]
runCodexInWindowsSubsystemForLinux = true
integratedTerminalShell = "wsl"

The WSL-side CLI is also installed as standalone and available through a compatibility wrapper:

/usr/local/bin/codex -> /home/<wsl-user>/.local/bin/codex
codex-cli 0.142.5

What issue are you seeing?

codex doctor reports that rollout files are missing from the state DB thread inventory, even though the state databases are healthy and the rollout files exist on disk.

This is not limited to old archived sessions. The missing set includes recent/current Codex Desktop sessions from the same day, including a large active Desktop thread in the current workspace.

There is no codex doctor repair, reindex, or equivalent command exposed by the CLI, so there does not appear to be a safe supported way to reconcile the state DB with the existing rollout files.

Doctor report excerpt

Codex Doctor v0.142.5 · windows-x86_64

Environment
  ✓ state        databases healthy
      state DB                 C:\Users\<USER>\.codex\state_5.sqlite (file) · integrity ok
      log DB                   C:\Users\<USER>\.codex\logs_2.sqlite (file) · integrity ok
      goals DB                 C:\Users\<USER>\.codex\goals_1.sqlite (file) · integrity ok
      memories DB              C:\Users\<USER>\.codex\memories_1.sqlite (file) · integrity ok
      active rollouts          166 files · 371.13 MB
      archived rollouts        12 files · 313.32 MB

  ⚠ threads      rollout files are missing from the state DB
      rollout DB active files  166
      rollout DB archived files 12
      rollout DB rows          121
      rollout DB active rows   116
      rollout DB archived rows 5
      rollout DB missing active rows 50
      rollout DB missing archived rows 7
      rollout DB stale rows    0
      rollout DB scan errors   0
      rollout DB malformed file names 0
      rollout DB duplicate rollout thread ids 0
      rollout DB duplicate DB paths 0
      rollout DB sources       subagent:other=56, vscode=46, subagent:thread_spawn=12, cli=7

Local reconciliation results

I compared the filesystem rollout files with references in state_5.sqlite in read-only mode. The result exactly matches codex doctor:

Rollout files total: 178
Indexed according to DB comparison: 121
Missing according to DB comparison: 57

Missing by kind:
  active: 50
  archived: 7

Missing by month:
  2026-05: 13
  2026-06: 34
  2026-07: 10

A deeper read-only analysis of the 57 unindexed rollout files shows they are not just old cleanup leftovers:

Top source groups:
  47x Codex Desktop=1
  8x vscode=1; Codex Desktop=1
  1x vscode=10; Codex Desktop=10
  1x vscode=4; Codex Desktop=4

Top model groups:
  28x codex-auto-review=2
  10x codex-auto-review=4
  4x gpt-5.5=2
  2x gpt-5.5=20
  1x gpt-5.5=456

Recent examples from July 2026 include current/recent Desktop sessions:

2026-07-07 18:26:53  active  3.42 MB  2121 lines  model gpt-5.5=456
cwd: C:\Users\<USER>\Documents\Codex\2026-07-07\i

2026-07-07 14:19:57  active  0.71 MB  310 lines  model gpt-5.5=20
cwd: /home/<wsl-user>/work/journal

2026-07-07 16:12:00  active  0.15 MB  12 lines  model codex-auto-review=2
cwd: C:\Users\<USER>\Documents\Codex\2026-07-07\i

Steps to reproduce / observed workflow

  1. Use Codex Desktop on Windows with WSL agent mode enabled:

    [desktop]
    runCodexInWindowsSubsystemForLinux = true
    integratedTerminalShell = "wsl"
  2. Work normally across Windows Desktop sessions and WSL-backed sessions.

  3. Run:

    codex doctor --summary
  4. Observe:

    ⚠ threads      rollout files are missing from the state DB
    
  5. Run:

    codex doctor --all --no-color
  6. Observe that the missing rollout files include recent/current Desktop rollouts, not only old archived history.

Expected behavior

Either:

  1. Every valid rollout file written by Codex Desktop/CLI should have a matching row in the state DB thread inventory, or
  2. Codex should provide a supported repair/reindex command that can safely reconcile state_5.sqlite with existing rollout files, or
  3. codex doctor should classify known intentionally-unindexed internal rollouts separately instead of warning that thread inventory differs.

Actual behavior

  • Rollout files exist on disk.
  • State databases pass integrity checks.
  • codex doctor reports 57 rollout files missing from the state DB.
  • Missing files include current/recent active Desktop sessions.
  • There is no exposed repair/reindex command:
codex doctor --help     # diagnostics only
codex --help            # resume/archive/delete exist, but no repair/reindex command

Why this matters

This leaves users with a degraded doctor report and no clear safe remediation. Moving or deleting rollout files can hide the warning but risks losing recent/current chat history. Editing SQLite manually is unsafe and likely to be overwritten or made inconsistent by the app.

A supported reconciliation path would be useful, especially for active Windows Desktop + WSL users.

Related issues

This looks related to, but distinct from, the stale-row side of thread inventory drift reported in:

This report is the opposite direction: rollout files exist, but state DB rows are missing. It also appears in a Windows Desktop + WSL setup where recent Desktop rollouts are affected.

There is also a separate Windows/WSL MCP path issue where Desktop rewrites node_repl to a /mnt/c/.../node_repl.exe path that native PowerShell codex doctor cannot resolve; that appears to be a separate WSL/Desktop config issue and is not the main focus of this report.

Activity

  1. added
    bugSomething isn't working
    appIssues related to the Codex desktop app
    windows-osIssues related to Codex on Windows systems
    sessionIssues involving session (thread) management, resuming, forking, naming, archiving
    on Jul 7, 2026
  2. atlantho commented on Jul 7, 2026

    @atlantho
    Author

    Thanks for the duplicate suggestions. I reviewed #30347, #30385, and #30163.

    My current reading is that this issue is related but not an exact duplicate:

    This report is specifically about codex doctor / state.rollout_db_parity finding rollout files that exist on disk but have no matching rows in state_5.sqlite, while all SQLite DB integrity checks pass. In this environment the mismatch includes current/recent Windows Desktop + WSL-agent sessions, and the doctor data shows:

    rollout DB active files  166
    rollout DB archived files 12
    rollout DB rows          121
    rollout DB active rows   116
    rollout DB archived rows 5
    rollout DB missing active rows 50
    rollout DB missing archived rows 7
    rollout DB stale rows    0
    

    A local read-only reconciliation against state_5.sqlite reproduced the same 57 missing rows exactly:

    Rollout files total: 178
    Indexed according to DB comparison: 121
    Missing according to DB comparison: 57
    Missing by kind: active=50, archived=7
    Missing by month: 2026-05=13, 2026-06=34, 2026-07=10
    

    So the overlap is local thread inventory drift, but the concrete direction here is: rollout files exist, DB rows are missing. This is distinct from stale DB rows pointing to missing rollout files and from UI/sidebar-only visibility problems. A supported repair/reindex command would likely help all of these cases, but I do not think this issue should be closed as a direct duplicate unless maintainers want to consolidate all state/rollout parity drift under one canonical issue.

  3. atlantho commented on Jul 8, 2026

    @atlantho
    Author

    Additional impact note: this is not just a cosmetic codex doctor warning in my setup.

    When the thread/rollout inventory is in this state:

    threads: rollout files are missing from the state DB
    

    Browser Use in the Codex Desktop app is affected and does not work reliably. That makes the issue more severe than a stale-index warning, because Browser Use is a core Desktop App workflow.

    The important distinction is that the Doctor warning may look optional/degraded, but the user-visible behavior is loss of a core capability. Please treat this as a functional regression in the Desktop App state/thread inventory path, not only as a cleanup/reporting issue.

  4. atlantho commented on Jul 8, 2026

    @atlantho
    Author

    Version update: this still reproduces after updating Codex from 0.142.5 to 0.143.0.

    So the issue is not limited to the originally reported 0.142.5 install. After the update, codex doctor --summary still reports the thread/rollout inventory warning, and the Browser Use impact remains relevant.

  5. come2ry commented on Jul 21, 2026

    @come2ry

    Confirmed on macOS with codex-cli 0.145.0 (upgraded from 0.144.6). This is not Windows/WSL-specific.

    codex doctor --json reports:

    state.rollout_db_parity: warning
    active rollout files: 2429
    active DB rows: 2253
    missing active rows: 176
    missing archived rows: 0
    stale rows: 0
    duplicate DB paths: 0
    duplicate rollout thread IDs: 0
    scan errors: 1 (one legacy rollout has no usable header record)
    state DB integrity: ok
    

    Before upgrading, a read-only filesystem/SQLite comparison on 0.144.6 found 177 rollout IDs absent from state_5.sqlite, with no DB row pointing to a missing rollout. The one-count difference is the malformed-header rollout that 0.145.0 doctor correctly excludes from the valid inventory.

    The user-visible symptom was a burst of identical warnings while the Desktop/App host resolved historical thread IDs:

    WARN codex_rollout::list: state db discrepancy during find_thread_path_by_id_str_in_subdir: falling_back
    

    The upstream source explains this precisely: find_thread_path_by_id_str_in_subdir falls back to the rollout filesystem when the DB lookup has no row, then calls read_repair_rollout_path for the accessed thread. This repairs only threads that happen to be resolved; codex doctor still exposes no supported bulk repair/reindex action, so 176 valid active rollouts remain unindexed after the upgrade and doctor run.

    For comparison, two isolated long-lived Codex profile homes on the same machine are fully consistent (109/109 and 17/17), which rules out general filesystem permissions or SQLite integrity as the cause.

    Requested acceptance criteria remain: either prevent valid rollouts from being left unindexed, or provide a supported idempotent repair/reindex command that reconciles every valid rollout without direct user SQL edits and verifies parity afterwards.

  6. glebsa8 commented on Jul 21, 2026

    @glebsa8

    same happened to me, experienced on macos with 0.145 stable and codex desktop 26.715.70719. @atlantho could you pls rename the the issue and put relevant tags?

    nvm, mine issue is a bit different as I see now when I dug deeper, the log is same though. codex doctor shows no warnings, but notes

    Notes
       ⚠ rollouts     877 active files · 1.33 GB on disk
    
  7. changed the title [-]Codex Desktop leaves rollout files unindexed in state DB, including current Windows/WSL Desktop sessions[/-] [+]Codex leaves valid rollout files unindexed in state DB and lacks supported reindex repair[/+] on Jul 22, 2026
  8. atlantho commented on Jul 22, 2026

    @atlantho
    Author

    I updated the title to make the scope platform-neutral now that there is a confirmed macOS reproduction with the same rollout DB parity direction.

    Current title:

    Codex leaves valid rollout files unindexed in state DB and lacks supported reindex repair

    I cannot apply repository labels myself, but based on the current evidence I think the issue should probably be labeled with:

    • "macOS", because come2ry confirmed the same "state.rollout_db_parity" warning on macOS with valid rollout files missing from "state_5.sqlite".
    • "regression", because multiple reports tie the mismatch to upgrades/update-time state drift.

    I would keep "windows-os" as well, because the original reproduction remains Windows Desktop + WSL-backed runtime. The issue is now best understood as cross-platform rollout/state DB parity drift rather than Windows-only behavior.

    I still do not think #30347, #30385, or #30163 are exact duplicates. They overlap in the local thread/session inventory family, but this report is specifically about valid rollout files existing on disk while the state DB lacks corresponding rows, with SQLite integrity otherwise OK, and no supported bulk repair/reindex command available.

  9. bbingz commented on Jul 24, 2026

    @bbingz

    Doctor already computes the repair diff - the missing surface is a fixer, not a detector

    Hit a related state.rollout_db_parity: warning on macOS in July 2026. The implementation-cost angle seems under-raised in the thread, so sharing what I found.

    codex doctor's state.rollout_db_parity check already tallies the exact diff a repair command would apply - missing_active/missing_archived/stale_rows/duplicates/scan-errors (computed via missing_rollout_paths in thread_inventory.rs:240-241) - but the missing-rows DoctorIssue (:369-382, "rollout files are missing from the state DB") carries .measured/.expected and no .remedy, while the missing-state-db (:196), duplicate (:417), and permission (:215/:433) cases all carry one. run_doctor is contractually read-only (doctor.rs:304, "It does not repair issues"), DoctorCommand (:151) exposes only json/summary/all/no_color/ascii flags, and enum Subcommand (main.rs:123) has no Reindex/Repair/Sync variant. So the work reads less as "build a reconciliation engine" and more as expose the diff doctor already computes to a fixer loop over reconcile_rollout (state_db.rs:486, the per-file upsert primitive). read_repair_rollout_path (:564) already does per-thread lazy read-repair (as @come2ry also observed) - a bulk reindex would be the eager equivalent. The diff is the plan, but not blindly applicable - it inherits doctor's classification gaps (see Scope) - and backfill's terminal mark_backfill_complete (backfill.rs:82) would need a reset/re-arm path for a reindex to revisit files already marked complete.

    What the local incident showed (evidence, not a prescription)

    My incident was path drift - a CODEX_HOME / session-directory change left rollout_path entries dangling - not corruption (PRAGMA integrity_check was ok throughout). This may be a different trigger than #31433's upgrade-associated missing-rows; I'm citing it only as independent corroboration of the diagnostic and the cost argument.

    • integrity_check was ok - the DB was structurally fine; the gap was file/path drift, not corruption. A genuinely-malformed-DB case (Codex Desktop loses visible chat history when local state SQLite index is corrupted #27363) would need a different path.
    • Doctor reported stale_rows = 934 (931 active rollout files whose recorded path no longer resolved + 3 genuinely-dead archived rows). Path drift inflates both stale_rows and missing_active in lockstep - the DB row points at a stale location while the file sits at the new one.
    • A repair must run against live state and re-verify: an earlier same-day snapshot reported 1,386 stale / 1,383 recoverable; live state at repair time showed 934. Counts drift while sessions run.
    • Applying doctor's computed diff cleared the warning: stale_rows 934 -> 0; active files/rows 2218/2218; archived 2/2; missing_active/missing_archived = 0; integrity_check = ok; wal_checkpoint(TRUNCATE) = 0|0|0. The 931 files were copied back to the subpaths their DB rows expected (0 overwrites); the 3 dead archived rows were removed.
    • What was not done: no DB file deletion, no bulk row delete, no overwriting of existing active rollouts, no trusting of the earlier snapshot's counts. Backups were taken before any write (ephemeral-directory backups do not survive reboot on macOS - a supported command should write to a durable location).

    To be explicit: this was a private one-off and not a recommended fix. Manual per-file reconciliation does not scale and is unsafe for most users. The point is that doctor's diff was the repair plan - the outcome validates the cost argument above, not a methodology to replicate.

    A genuinely-dead-row safety check I used (proposed, not a verified invariant - there may be reference tables I didn't check): a row is a deletion candidate only if its file is found at no accessible location and it has 0 references in thread_spawn_edges and 0 in thread_dynamic_tools, both verified zero first.

    Two unconfirmed root-cause candidates

    I could not attribute #31433 to a specific code change (source search indexes files, not issue/PR histories). Two behaviors confirmed in main as of 2026-07-24 could produce missing-rows under different signatures:

    • (a) Backfill is terminal. backfill_sessions_with_lease (metadata.rs:154) early-exits when status == Complete (:174) and retains only files with watermark > last_watermark (:243); mark_backfill_complete (backfill.rs:82) is terminal. Signature: a rollout missing at completion time stays permanently unindexed - rows never appear.
    • (b) list_threads_db drops rows. When existing_rollout_path (state_db.rs:427) returns None, it calls ctx.delete_thread (:439), emitting stale_db_path_dropped (:438). Signature: rows appear then disappear. My path-drift incident independently supports this direction - a moved file makes the path lookup fail, so the row gets dropped on the next listing.

    These behaviors are confirmed in main; whether either caused #31433's missing-rows is the hypothesis. Line numbers will drift; symbol names are the stable anchors. Static reading only - I could not build/run codex-rs.

    Scope

    A reindex fixes file<->DB parity. It does not fix DB-vs-UI listing drift (#27159/#25463/#30312) or creation-time materialization failures where a rollout was never written (#32728/#30924; #33120 is archive-time, also out of scope). It is distinct from #31074's stale-rows direction (DB row exists, file gone) - #31433 is missing-rows (file exists, no DB row) - though both are drift directions of the same gap.

    A reindex must also correctly ingest legacy pre-session_meta rollouts (#26877 - doctor currently flags valid legacy rollouts as scan errors) and must not act on sandbox-constrained false-corruption signals (#33145), or it inherits doctor's existing classification bugs and becomes unsafe to run. #28068 closes the obvious escape hatch: deleting the state DB regenerates it but does not back-scan historical rollouts - no supported path exists, not even a destructive one.

    Happy to expand any of the above as design discussion if useful. A full redacted codex doctor --json from the incident is available privately.

  10. bbingz commented on Jul 24, 2026

    @bbingz

    Update: root cause narrowed — structural non-transactional gap, exposed by #22236 + #22899

    Following up on my earlier comment, a deeper source trace narrows the root cause. The two candidates I flagged there — terminal mark_backfill_complete (a) and list_threads_db dropping rows via delete_thread/stale_db_path_dropped (b) — are both refuted by the evidence below. The actual mechanism is a non-transactional write gap, amplified by two May-2026 changes.

    Mechanism (longstanding, new sessions). thread_start (thread_processor.rs::thread_start_task) never eagerly creates a threads-table row — it only calls thread_watch_manager.upsert_thread_silently, which is in-memory (ThreadWatchState HashMap, zero SQLite). Row creation is deferred to the first turn's append_items (live_thread.rs), which performs two independent, non-transactional durable operations in sequence:

    1. persist_appended_items → writes the JSONL rollout file to disk;
    2. observe_appended_items → update_thread_metadata → apply_metadata_update → state_db.upsert_thread → creates the row.

    A crash/quit between (1) and (2) leaves exactly the reported state: rollout file present, threads-table row absent. read_repair_rollout_path repairs it lazily per-thread (the falling_back path @come2ry's log shows), which is why per-thread reindex works but there is no bulk repair.

    Amplifier — #22899 (2026-05-15, "Soften SQLite metadata sync failures"). The first-row patch carries observed/create-time metadata (created_at/source/cli_version/git_info, title/preview/token_usage/cwd), so has_observed_metadata_facts makes require_sqlite_write = sqlite_write_failure_should_block(patch) || paginated evaluate FALSE. Any transient upsert_thread failure (e.g. SQLITE_BUSY under multi-process contention) therefore hits the warn-only swallow arm (update_thread_metadata.rs) → returns Ok(()), and mark_pending_update_applied clears the create-time patch — created_at/source/cli_version/git_info are permanently lost. The swallow is silent: warn! only, no telemetry/counter/retry. This is not a guess about intent: #22899's own root-cause note states the append-derived SQLite writes "now propagated through the live thread flush path, so a corrupted optional state DB could surface as a transcript persistence warning even when JSONL writes still succeeded" — i.e. JSONL (rollout file) succeeds while the SQLite row fails, by design best-effort.

    Introducer — #22236 (2026-05-13, "Unify thread metadata updates above store"). This moved "the implicit metadata updates triggered by appending rollout items" out of RolloutRecorder (local-threadstore-specific) into a ThreadMetadataSync helper at the LiveThread layer, with LiveThread calling append_items and update_metadata separately (quoting the PR). The previous RolloutRecorder path ran sync_thread_state_after_write on every resumed flush and (re)created a missing threads-table row from the rollout file's own contents (builder_from_items → touch_thread_updated_at → on miss apply_rollout_items → upsert_thread) — an independent self-healing backstop. Post-#22236, RolloutRecorder is a pure JSONL writer; sync_materialized_rollout_path only UPDATEs existing rows (early-returns Ok when get_thread is None). So nothing recreates the row at resume — a transient one-session miss becomes permanent, accumulating across launches.

    Timeline fit. #22236 merged 2026-05-13, #22899 merged 2026-05-15. @atlantho's missing-by-month (57 missing: 2026-05=13, 06=34, 07=10) starts exactly at #22236. @come2ry found 177 missing on 0.144.6 before upgrading — consistent with "upgrade-exposed, not introduced": the structural gap was always present, but #22236 removed the next-launch self-heal that previously masked it, so misses began accumulating permanently from May.

    Earlier candidates refuted.

    • (a) terminal mark_backfill_complete: backfill is a one-shot startup scan, terminal after claiming, and covers only pre-existing files — it cannot explain same-day current-session loss. The 30s STARTUP_BACKFILL_WAIT_TIMEOUT is also not the cause: try_init returns Err on timeout and the app-server fails to start rather than running with state_db=None.
    • (b) list_threads_db dropping rows: stale_db_path_dropped deletes only rows whose rollout file is missing (opposite direction); both reports show stale_rows = 0, and missing threads retain rollout files. falling_back is the non-destructive read_repair UPSERT, not a delete.
    • Ephemeral subagents: ephemeral threads produce no rollout file and structurally cannot enter the doctor's missing set — missing_rollout_paths iterates on-disk scan files, so all 57 missing have rollout files by definition.

    Caveat. Whether the missing set is dominated by resumed sessions (favors #22236) or new sessions (favors the longstanding non-transactional gap) is not distinguishable from source alone. The closing check needs per-file data: a thread_history DB entry for that thread_id predating the rollout file's mtime ⇒ resumed; or the rollout's first SessionMeta.created_at equal to the file's ctime ⇒ new. Either way the fix surface is the same.

    Fix surface (builds on the earlier comment). Doctor already computes missing_rollout_paths; a bulk reindex loop over reconcile_rollout/read_repair_rollout_path is still the eager equivalent of the lazy repair. Two additions the trace suggests:

    • a telemetry counter on the warn-only arm to categorize the Internal errors (busy/locked/no-such-column/full/readonly) seen in the field — currently fully silent;
    • (harder) make the first-row SQLite upsert transactional with the rollout flush, or re-add a resume-time self-heal equivalent to the pre-Unify thread metadata updates above store #22236 sync_thread_state_after_write.

    Static source-level as of 2026-07-24; line numbers will drift, symbol names are the stable anchors. Happy to refine if maintainers can share which upsert error dominates in the wild.

  11. samlogic-ship commented on Jul 31, 2026

    @samlogic-ship

    Linux confirmation on Codex 0.146.0

    This also reproduces on a long-lived Forge host using the standalone Linux x86_64 build of codex-cli 0.146.0. A fresh, sanitized codex doctor --json run on 2026-07-31 reports:

    state.rollout_db_parity: warning
    state DB integrity: ok
    active rollout files: 1542
    active DB rows: 671
    missing active rows: 871
    archived rollout files: 374
    archived DB rows: 236
    missing archived rows: 138
    stale rows: 0
    scan errors: 0
    malformed file names: 0
    duplicate rollout thread IDs: 220
    duplicate DB paths: 0
    sources: subagent:thread_spawn=492, vscode=370, exec=45
    

    This environment contains both .jsonl and preserved .jsonl.zst rollouts. Current tasks, the app-server, and SQLite integrity checks still work, so the warning is inventory drift rather than general database corruption.

    The duplicate-ID dimension is important. A supported repair cannot only insert the 1,009 missing rows. It also needs deterministic handling for multiple rollout files carrying the same thread ID, while preserving the authoritative transcript and avoiding data loss.

    Requested repair behavior:

    1. Scan active and archived .jsonl and .jsonl.zst rollouts.
    2. Rebuild missing threads rows using the same supported reconciliation logic as lazy read repair.
    3. Resolve or explicitly quarantine duplicate thread IDs deterministically.
    4. Run transactionally or create a recoverable backup, ideally with a dry-run mode.
    5. Re-run parity verification and report the remaining exceptions.
    6. Prevent new drift by retrying or self-healing failed metadata upserts.

    codex doctor, codex debug, and codex app-server in 0.146.0 still expose no supported repair or reindex command. I did not modify the live SQLite database manually and omitted paths, titles, rollout contents, and sample thread IDs from this public report.

  12. suryatejaKONDLA commented on Aug 15, 2026

    @suryatejaKONDLA

    Additional cross-OS reproduction that looks like the same underlying state-DB reconciliation problem.

    Environment

    • Windows + Ubuntu dual boot
    • ChatGPT Linux package: 26.810.52044 (amd64)
    • The same physical NTFS volume is used as shared CODEX_HOME
    • Separate local CODEX_SQLITE_HOME per OS to avoid SQLite/WAL on NTFS

    Example layout:

    Windows:
    CODEX_HOME=D:\.codex
    CODEX_SQLITE_HOME=C:\Users\<user>\.codex-sqlite
    
    Linux:
    CODEX_HOME=/run/media/<user>/<shared-volume>/.codex
    CODEX_SQLITE_HOME=/home/<user>/.codex-sqlite
    

    Reproduction

    1. Create a new Codex thread on Linux and send a message.
    2. Reboot into Windows and open Codex.
    3. The newly-created Linux thread is not shown in the Windows thread list.
    4. Rebuilding/deleting the local Windows SQLite state causes the thread to appear, and the thread contents/messages are correct from the shared rollout files.
    5. Create another new thread on Windows and send a message.
    6. Reboot into Linux and open Codex.
    7. The new Windows thread is not shown in Linux either.

    The shared rollout/session files are present and the actual messages are usable once the local state DB is reconciled. The issue is that the already-completed local state DB does not notice newly-added rollout files written by the other OS/client.

    Confirmed workaround

    On Linux, after switching from Windows, this makes the missing new thread appear without deleting the SQLite files:

    sqlite3 ~/.codex-sqlite/state_5.sqlite \
      "UPDATE backfill_state SET status='pending', updated_at=0 WHERE id=1;"

    Then launch Codex normally. Keeping last_watermark intact causes an incremental backfill, and the newly-added rollout is indexed. After completion:

    SELECT status,last_watermark,last_success_at FROM backfill_state;

    returns complete|... and the cross-OS thread appears.

    A full local DB rebuild also works, but obviously should not be necessary.

    Related startup behavior

    While testing a fresh local CODEX_SQLITE_HOME, I also hit:

    state db backfill is running at <shared CODEX_HOME>; waiting up to 30s
    Codex app-server initialize handshake timed out
    

    After allowing the bundled Codex CLI to complete the initial backfill once, the Desktop app started normally.

    Expected behavior

    When valid rollout/session files are added to CODEX_HOME by another Codex client / another OS, Codex should automatically reconcile the local state DB on startup (preferably incrementally from the previous watermark).

    Alternatively, please expose a supported command such as:

    codex reindex
    codex doctor --repair-threads
    

    so users do not have to delete SQLite databases or manually modify backfill_state.

    This use case makes the underlying issue very visible because the shared CODEX_HOME is intentionally common while the SQLite state is necessarily local to each OS.

  13. pomazanbohdan commented on Aug 23, 2026

    @pomazanbohdan

    Our Windows cleanup case reinforces this projection boundary: rollout JSONL is the canonical record, while state DB history tables are derived projections. Safe repair should first produce a read-only file/DB/ordinal diff, then mutate only with a backup and exact postconditions; this connects to #35746, #40178, and the agent-state drift in #37042.

  14. JaredTheHammer commented on Aug 25, 2026

    @JaredTheHammer

    Additional Windows evidence for the missing repair path. Codex Desktop 26.818.8289.0 left valid raw rollouts with projection cursors stopped at duplicate ordinal boundaries. There was no supported reindex or repair command, so recovery required a backup-first, narrowly guarded SQLite cursor repair while preserving every raw JSONL file. The repaired database passed integrity checks and the app-server reconnected.

    A supported doctor or reindex command should detect and reconcile these ordinal and byte-offset mismatches without requiring manual SQLite edits.

  15. DJNgoma commented on Aug 28, 2026

    @DJNgoma

    Confirmed on macOS with Codex CLI 0.150.1

    I can confirm the same rollout/state-DB parity problem on macOS.

    Environment:

    • macOS 27.0.0, Apple Silicon
    • Codex CLI 0.150.1
    • ChatGPT Desktop 26.820.60940
    • Bundled Codex CLI 0.150.0-alpha.8

    Current codex doctor --json result:

    state.rollout_db_parity: warning
    active rollout files: 1059
    active DB rows: 1009
    archived rollout files: 2762
    archived DB rows: 2758
    missing active rows: 50
    missing archived rows: 4
    stale rows: 0
    scan errors: 0
    malformed file names: 0
    duplicate rollout thread IDs: 2
    duplicate DB paths: 0
    

    A separate read-only comparison between the rollout filesystem and state_5.sqlite reproduced Doctor’s result exactly: 54 valid rollout files exist without matching thread rows.

    Breakdown:

    • 50 active and 4 archived
    • 48 originated from codex_exec
    • 6 originated from Codex Desktop
    • Every affected file had a usable session_meta header
    • SQLite integrity checks remain ok

    The mismatch is confined to Codex-owned storage under $CODEX_HOME: rollout JSONL files and Codex’s state_5.sqlite. Some historical Codex threads used alternative model-provider routes, but those values are only routing metadata stored inside the Codex rollout. I found no evidence that native provider applications, credentials, or histories are involved.

    No manual SQLite edits, rollout deletion, concatenation, or migration workaround has been attempted.

    A supported, idempotent reindex/reconciliation command would still be the safest resolution. Ideally it should:

    1. Back up the SQLite state first.
    2. Reconstruct missing rows from valid rollout headers.
    3. Handle duplicates explicitly rather than silently selecting one.
    4. Re-run parity and SQLite integrity checks after reconciliation.
  16. frankhounrat-afk commented on Aug 31, 2026

    @frankhounrat-afk

    Additional read-only case from Windows 11 / Codex CLI 0.150.1 that may help distinguish a true orphan rollout from a paginated-history base.

    codex doctor --all reported:

    rollout DB active files              72
    rollout DB rows                      72
    rollout DB active rows               71
    rollout DB missing active rows        1
    rollout DB duplicate rollout thread ids 1
    state DB integrity                   ok
    

    The sample thread_id associated with both warnings matched two physical rollout files. Reading only each first session_meta record showed that both files intentionally declared the same logical thread ID, source (vscode), thread source (user), originator (Codex Desktop), and workspace. They were created by different Desktop/CLI builds on different days.

    A read-only query of state_5.sqlite returned exactly one canonical threads row for that logical thread, and its rollout_path pointed to the newer rollout.

    The key detail is that the newer rollout's first session_meta record contains:

    "history_mode": "paginated",
    "history_base": {
      "thread_id": "<same-logical-thread-id>",
      "end_ordinal_exclusive": 5754,
      "end_byte_offset": 112391183
    }

    The older rollout was ~112.4 MB, so the declared end_byte_offset falls inside that older file. This strongly indicates that the older rollout, although not represented by its own current DB row, is the inherited history base for the newer canonical rollout rather than disposable duplicate data.

    Practical implication: deleting/moving an unindexed rollout merely to clear missing active rows / duplicate rollout thread ids can be unsafe when the canonical rollout has history_mode=paginated and history_base.thread_id points to the same logical thread. It may remove history needed to materialize the complete thread.

    It would be useful if state.rollout_db_parity recognized this relationship and either:

    1. excluded a valid history_base rollout from the generic missing/duplicate warning, or
    2. classified it separately as an inherited paginated-history base.

    Any future repair/reindex command should also preserve such base rollouts rather than treating every unindexed file as an orphan.

  17. metalbladex4 commented on Sep 9, 2026

    @metalbladex4

    Additional evidence on Codex CLI 0.153.4, Ubuntu 24.04/WSL2, VS Code

    A read-only investigation found that Doctor's two warnings describe a valid three-file history chain:

    • Three rollout files share one logical thread ID but have distinct rollout identities.
    • The database correctly selects the newest rollout.
    • Its history_base references the intermediate rollout, which references the original rollout.
    • Doctor reports the two inherited files as missing database rows and flags the shared thread ID as a duplicate.
    • Database integrity passes. There are no duplicate database paths, stale rows, archive mismatches, malformed filenames, or scan errors.

    Sanitized structure: current rollout C -> inherited rollout B -> original rollout A.

    The rust-v0.153.4 rollout implementation supports separate rollout identities, while Doctor's inventory check appears to assume one physical rollout per logical thread.

    Please make the check history-chain-aware: distinguish valid inherited rollouts from genuinely unindexed files, while retaining warnings for missing bases, cycles, conflicting identities, and broken references.

    No conversation files or database rows were modified. Moving or deleting the inherited files merely to clear these warnings could break history resolution.

    Source references:

  18. softerist commented on Sep 22, 2026

    @softerist

    Additional native Windows evidence (no WSL agent mode) from Windows 11 Enterprise x64, Codex Desktop 26.917.6896.0, and codex-cli 0.155.0-alpha.16:

    codex doctor --no-color reports healthy state_5.sqlite and thread_history_1.sqlite integrity, with zero rollout scan errors and zero malformed file names. Its thread inventory counts are:

    Measure Count
    Active rollout files 274
    Archived rollout files 985
    State DB rows (active / archived) 1,220 (271 / 949)
    Files without DB rows (active / archived) 4 / 36
    Stale DB rows 1
    Duplicate rollout thread IDs 23
    Archive mismatches / duplicate DB paths 0 / 0

    For one active rollout that doctor counts as missing from the state DB, a codex migrate-rollouts dry run reported already_paginated and bytes_processed: 0. This suggests the legacy rollout migration does not address that case; I did not run --apply. I have not edited or removed rollout files or database rows. This extends the original report to native Windows and shows unindexed files, one stale DB row, and duplicate rollout thread IDs in the same inventory. Is there a supported way to reconcile these records while preserving task history?

  19. MadKangYu commented on Sep 23, 2026

    @MadKangYu

    Latest readback at 2026-09-23 20:19 KST on macOS Apple Silicon with Codex CLI
    0.156.1: codex doctor reports 6,179 active rollout files and 6,178 active
    state DB rows, with one missing active
    row and one duplicate rollout thread ID. Stale rows, archive mismatches, scan
    errors, and duplicate DB paths are all zero. The duplicate ID corresponds to
    two valid paginated files: a base segment and a continuation whose
    session_meta.history_base points to the base boundary. The state DB has one
    row for the continuation, and the thread-history projection cursor matches the
    base segment's end boundary. Targeted codex migrate-rollouts inspection for
    this thread reports both files as already_paginated; the CLI exposes no
    supported inventory reindex or parity repair command. Could Doctor account
    for this history_base relationship, or provide a supported non-destructive
    repair? No rollout contents, thread IDs, local paths, credentials, or workspace
    data are included.


    This issue or PR was generated by LazyCodex.
    Tag: lazycodex-generated

  20. karloows commented on Sep 28, 2026

    @karloows

    I’m seeing the same warning on macOS with Codex CLI 0.157.1:

    ⚠ threads  2 issues - rollout files are missing from the state DB; duplicate thread inventory entries found
    rollout DB active files 1606
    rollout DB rows 1605
    rollout DB missing active rows 1
    rollout DB duplicate rollout thread ids 1
    rollout DB duplicate rollout thread id sample 01a0a86a-3f3c-7f03-b1da-6f1b692aab25
    

    The duplicate ID has two rollout files on disk: the original session file and a continuation file with a second ID suffix. The state DB points to the continuation. The databases pass integrity checks.

    I also ran codex migrate-rollouts --json --verbose; the sessions were reported as already_paginated, and the warning remained. There doesn’t appear to be a supported way to reconcile the inventory without risking session history.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    appIssues related to the Codex desktop appbugSomething isn't workingsessionIssues involving session (thread) management, resuming, forking, naming, archivingwindows-osIssues related to Codex on Windows systems

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions