Windows Desktop local state is not crash-safe after power loss: pins/projects reset, config regresses, future timestamps
What version of the Codex App are you using (From “About Codex” dialog)?
Codex Desktop Windows app package:
OpenAI.Codex_26.602.4764.0_x64__2p2nqsd0c76g0
Version: 26.602.4764.0
The app was updated before filing this report.
Additional local CLI present on the same machine:
codex-cli 0.125.0
What subscription do you have?
ChatGPT Pro
What platform is your computer?
Microsoft Windows 11 Pro
Version: 10.0.26200
Build: 26200
Architecture: x64
Filesystem: NTFS
What issue are you seeing?
After power loss / abrupt shutdown, Codex Desktop local state is repeatedly coming back in a partially reset or internally inconsistent state.
The user-visible symptoms are:
- pinned chats disappear from the sidebar;
- saved projects/workspaces disappear or collapse to a single workspace;
- some project views show
No chatseven though local conversations still exist; - the TUI/skills refresh can fail because
config.tomlregresses to an invalidservice_tier = "default"value for this installed version; - local metadata can get a far-future timestamp (
7026), making an old session look newer than real recent sessions.
This has happened multiple times after power loss. It looks like the local Desktop/profile state under %USERPROFILE%\.codex is not crash-safe across abrupt shutdowns. The underlying conversations are generally still recoverable from local SQLite/session files, but the UI state and indexes become misleading or broken.
Concrete local evidence
The affected local state directory is %USERPROFILE%\.codex.
1. .codex-global-state.json was rewritten to a minimal state
Before repair, the current .codex-global-state.json had effectively collapsed to one workspace:
file: %USERPROFILE%\.codex\.codex-global-state.pre-repair-20260606-070944.json
size: 2,053 bytes
pinned-thread-ids: 1
project-order: 1
electron-saved-workspace-roots: 1
thread-workspace-root-hints: 0
active-workspace-roots: [%USERPROFILE%]
After reconstructing from a known-good backup and state_5.sqlite, the repaired state contained:
file: %USERPROFILE%\.codex\.codex-global-state.backup-20260606-070944.repaired.json
size: 102,112 bytes
pinned-thread-ids: 11
project-order: 27
electron-saved-workspace-roots: 27
thread-workspace-root-hints: 675
Current post-repair state, after reopening the app, remains healthy:
pinned-thread-ids: 13
project-order: 28
electron-saved-workspace-roots: 27
thread-workspace-root-hints: 675
example project-specific hints: 3 for a project that previously showed `No chats`
The repaired JSON is UTF-8 without BOM. The first bytes are:
123,13,10
2. config.toml regressed to service_tier = "default"
The broken config contained this at the top:
model = "gpt-5.5"
model_reasoning_effort = "xhigh"
personality = "pragmatic"
sandbox_mode = "danger-full-access"
approval_policy = "never"
service_tier = "default"
The local error was:
failed to refresh skills: skills/list failed in TUI: skills/list failed: failed to reload config: C:\Users\<USER>\.codex\config.toml:6:16: unknown variant `default`, expected `fast` or `flex`
Restoring a previous fixed backup of config.toml removed the parse error. The current restored file no longer contains service_tier = "default".
3. A local thread and version cache jumped to year 7026
Before repair, one local thread had:
id: 911d47ec-a3a4-7503-b8ae-3f47cecabbd4
cwd: <redacted project path>
updated_utc: 7026-02-04 18:32:49
updated_ms: 159554946769000
rollout_path: %USERPROFILE%\.codex\sessions\7026\02\04\rollout-7026-02-04T15-32-49-911d47ec-a3a4-7503-b8ae-3f47cecabbd4.jsonl
version.json also had a last_checked_at timestamp in 7026:
{
"latest_version": "0.96.0",
"last_checked_at": "7026-02-04T18:32:48.404538600Z",
"dismissed_version": null
}
The 7026 session file contained only 4 metadata/instruction lines, not meaningful conversation content. After backing up the database and file, I moved it to the matching 2026 path and updated the SQLite row to a 2026 timestamp.
Post-repair validation:
future files under %USERPROFILE%\.codex: 0
future threads in state_5.sqlite: 0
4. Local conversation data was still present
The state database still contained many threads:
state_5.sqlite total threads: 791
active threads: 714
This looks like a local state/index/UI consistency problem rather than complete data deletion.
What steps can reproduce the bug?
This is tied to abrupt shutdown/power loss rather than a deterministic in-app action, but the observed sequence is:
- Use Codex Desktop on Windows with multiple saved workspaces/projects, pinned chats, and many local conversations.
- Leave Codex Desktop open with app-server/background processes active.
- Machine loses power or is abruptly shut down.
- Restart Windows and open Codex Desktop.
- Observe that the sidebar has lost pins and saved projects, or project views show
No chats. - In some cases, launch TUI/CLI or trigger skills refresh and observe config parsing failure from
service_tier = "default". - Inspect
%USERPROFILE%\.codexand compare:
.codex-global-state.jsonstate_5.sqlitesession_index.jsonlsessions/**/rollout-*.jsonlversion.json
The conversations remain mostly recoverable locally, but the UI state and metadata can be corrupted or reset.
What is the expected behavior?
Codex Desktop should make local state persistence crash-safe across abrupt shutdowns.
Specifically:
.codex-global-state.jsonshould not be replaced by a minimal state after a crash if recoverable state exists.- Writes to local JSON state should be atomic, for example write temp file, fsync, then rename.
config.tomlshould not regress to a value that the installed parser rejects.- Timestamps should be validated or clamped; a local session/version cache should not jump to year 7026.
- The app should detect drift between
.codex-global-state.json,state_5.sqlite,session_index.jsonl, and existing rollout files. - If project state is incomplete, Codex should expose a supported local repair/reindex command rather than making users inspect and patch SQLite/JSON manually.
- Project views should not display
No chatswhen matching active local threads exist instate_5.sqliteand rollout files exist on disk.
Actual behavior
After power loss, Codex Desktop can reopen with:
- pins reduced from 11+ to 1;
- saved projects reduced from dozens to 1;
- workspace hints removed;
- project chat views empty despite active rows in
state_5.sqlite; config.tomlcontainingservice_tier = "default", which this install rejects;- local metadata containing future year
7026.
Workaround used locally
With Codex Desktop closed:
- Back up the broken files/databases.
- Restore a known-good
config.tomlwithoutservice_tier = "default". - Rebuild
.codex-global-state.jsonfrom a known-good backup and active rows instate_5.sqlite. - Preserve and restore:
pinned-thread-idsproject-orderelectron-saved-workspace-rootsactive-workspace-rootsthread-workspace-root-hints
- Write JSON as UTF-8 without BOM.
- Move the
sessions\7026\...rollout to the equivalentsessions\2026\...path and update the corresponding SQLite row. - Restart Codex Desktop.
After that, pins/projects/project hints were visible again.
Related issues
This overlaps with several existing local state/sidebar/path reports, but I did not find an exact duplicate for the power-loss/crash-safety combination:
- #17540: Windows app older local threads disappear from sidebar/search while still present on disk.
- #24178: conversations become empty and resume fails with
C:\...vs\\?\C:\...stale path. - #25500: project sidebar shows
No chatsfor projects with older non-archived conversations. - #22452: local thread hidden/stale when
state_5.sqliteandsession_index.jsonldrift. - #24425: corrupted session JSON/history after crash; maintainer asked about power loss in discussion.
The distinct parts here are:
- reproducible trigger is power loss / abrupt shutdown;
.codex-global-state.jsoncollapses to a minimal state;config.tomlregresses to an invalidservice_tier = "default"for this version;- a local thread and version cache jumped to year
7026; - the same local profile needed coordinated repair across global state JSON, config TOML, SQLite, session index, and session paths.
Additional information
No raw logs_2.sqlite, auth.json, full config.toml, or rollout content is attached publicly because those files may contain private prompts, local project names, tokens, URLs, or account data.
I can provide redacted diagnostics or specific SQL/query output if maintainers say which fields are useful and safe to share.
20 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
I agree this is related to #26421, especially the non-atomic persistence / power-loss angle.
I do not think this is an exact duplicate, though. #26421 focuses on
config.tomlbecoming zero-filled with NUL bytes after an ungraceful shutdown. In this case,config.tomlwas still readable but regressed toservice_tier = "default", while.codex-global-state.jsonwas rewritten to a minimal state and lost pins/projects/workspace hints. The same incident also produced a future-year7026timestamp inversion.json, a session path, andstate_5.sqlite.So the shared root cause may be crash-unsafe local persistence, but the affected state is broader than
config.toml:.codex-global-state.json, session metadata, SQLite timestamps, and project/sidebar recovery are involved too.Additional update: repeated sidebar loss after recovery + destructive Windows hang dialog
I have continued investigating this locally after the original report. The behavior still looks broader than a single
config.tomlcorruption case.Installed version still affected
Current installed Windows package on the affected machine:
Chats can still exist locally while disappearing from the UI
After repairing
.codex-global-state.jsonand recovering old projects/pins, I was able to make old project chats visible again. However, some old project chats can disappear from the sidebar again later.The important detail is that this does not appear to be complete conversation deletion. Local rows and rollout/session files still exist. The problem appears to be that the Desktop sidebar/project list does not hydrate all local conversations from durable storage. It seems to depend on a combination of:
.codex-global-state.jsonproject-orderelectron-saved-workspace-rootsthread-workspace-root-hintspinned-thread-idsstate_5.sqlitethread metadataA temporary workaround was to add missing thread ids to
pinned-thread-ids. That forced the Desktop app to hydrate them. After unpinning, those chats moved back under their correct projects based on their workspace metadata. This strongly suggests pinning is acting as a hydration trigger, not as the real source of project membership.Local SQLite evidence
The affected profile currently has many active local threads whose
thread_sourceis stillNULL:Several older projects have only or mostly
thread_source IS NULLactive rows. These are the same kinds of projects that are more likely to show as empty or incomplete in the Desktop sidebar even though matching conversations exist instate_5.sqliteand rollout files.This may be a migration/indexing issue where older Desktop-created local conversations are still present but no longer pass the current sidebar/recent-thread filters unless they are pinned or otherwise explicitly hydrated.
Additional Windows-specific destructive failure mode
There is another Windows-specific way the crash/hang becomes destructive.
When Codex Desktop freezes while I am typing in the composer, Windows shows the standard
Codex is not respondingdialog. The focused/default button isEnd Process. If I press Enter at that exact moment intending to submit my prompt, Windows terminates Codex instead.Impact:
This is worse than a normal app hang because the default focused Windows action can terminate the app accidentally during normal typing. I have a screenshot of this state, but the raw screenshot contains private workspace paths and prompt content, so I am not attaching the unredacted image publicly.
Relation to newer reports
This also seems related to #27175, although this report predates it and I am currently on
26.602.4764.0. The overlapping symptoms are:What would help
In addition to atomic/crash-safe file writes, I think the Desktop app needs a supported recovery/reindex path for local state, for example:
.codex-global-state.jsonfromstate_5.sqlite+ existing rollout filesthread_source IS NULLDesktop threads to the current expected source kind, or include them in local recovery/searchThe current workaround requires manually inspecting and patching JSON/SQLite/session files, which is risky and not something users should have to do.
Additional update: GUI freeze improved after local log/plugin cleanup
I have one more data point from the same affected Windows profile. The Desktop app later started visually freezing / becoming unresponsive for many seconds, sometimes close to a minute, without a clear Windows
Application Hangevent being recorded.During one live freeze/startup investigation on the updated Windows app package:
I observed:
Codex.exewas still marked as responding by Windows, but it was temporarily consuming high CPU and significant disk reads.%USERPROFILE%\.codex\logs_2.sqlitewas about 668 MB.%USERPROFILE%\.codex\logs_2.sqlite-walhad grown to about 186 MB.The local
config.tomlstill hadbrowser-use@openai-bundledenabled, but the local bundled plugin cache only containedbrowser,chrome, andcomputer-use, notbrowser-use.A conservative mitigation helped noticeably:
%USERPROFILE%\.codex\logs_2.sqlite%USERPROFILE%\.codex\logs_2.sqlite-wal%USERPROFILE%\.codex\logs_2.sqlite-shm%USERPROFILE%\.codex\log\codex-tui.logbrowser-use@openai-bundledplugin entry inconfig.toml.After that, the app appeared noticeably more responsive.
I did not touch chat/session state during this mitigation, specifically not:
state_5.sqlite*sessions/archived_sessions/session_index.jsonlhistory.jsonl.codex-global-state.jsonThis suggests there may be a second contributing factor beyond the crash-safety/sidebar recovery problem: a large local log database plus repeated loading attempts for a configured-but-missing bundled plugin can make the Desktop app appear frozen or slow, and that freeze can lead to the destructive Windows
End Processflow described above.Follow-up: I later hit a stronger version of the same failure on
26.609.4994.0: a Crashpad dump was produced, the app restarted/updated from logs referencing26.609.3341.0, app-server initialization hitrestart-requiredand took about 127 seconds to recover, and active chats/tasks stopped. I added the concrete timeline and log snippets in a newer comment below.Additional update: Desktop crash/restart while active chats were running
This happened again on the same Windows profile, this time after the app had updated to:
From the UI side, it initially looked like Codex was still running but the GUI was not becoming visible. The process list showed
Codex.exeprocesses still alive, including one process with a valid main window handle. After the UI came back, the active chats/tasks had stopped and I had to restart the work.Local evidence suggests this was not just an off-screen or minimized window:
OpenAI.Codex_26.609.3341.0.2026-06-15 10:04:50local time:%LOCALAPPDATA%\Packages\OpenAI.Codex_2p2nqsd0c76g0\LocalCache\Roaming\Codex\web\Codex\Crashpad\reports\efe6e255-9215-4de3-a655-dcdb4c3361e6.dmpCodex.exeprocess started at2026-06-15 10:04:56local time.2026-06-15T13:04:58Z.initialize_handshake_timeoutwithconnectionError={"code":"restart-required"}.2026-06-15T13:07:07Z, after about 127 seconds.The old pre-restart log had repeated messages immediately before the crash/restart window:
There were also in-app browser/sidebar errors around the same period, including
Cannot find context with specified idandERR_FAILED (-2) loading 'about:blank', followed by browser sidebar page teardown.I am not attaching the raw dump or full logs publicly because they may contain local paths, conversation ids, and other sensitive data. The important symptom is that Codex can appear to still have processes alive, then restart/update underneath active work, and the active chats/tasks are lost or interrupted. This seems to reinforce the need for crash-safe session/process recovery, not only sidebar reindexing.
This issue maps closely to LS work on durable trajectories, crash-safe persistence, integrity evidence, and deterministic recovery.
A useful distinction is:
state file exists
≠ state is complete
≠ indexes agree
≠ the newest timestamp is trustworthy
A crash-safe local state model could treat SQLite, rollout files, session indexes, configuration, and UI projections as separate materializations of one durable trajectory.
authoritative event history
→ thread registry
→ workspace index
→ sidebar/project projection
→ cached configuration state
The central invariant would be:
«After an abrupt shutdown, Codex should recover from the newest internally consistent committed state—not from whichever file happens to have the latest modification time.»
A possible checkpoint manifest:
{
"schema_version": "local-state-checkpoint/v0.1",
"checkpoint_id": "checkpoint-20260624-1842",
"created_at": "2026-06-24T18:42:11Z",
"generation": 1842,
"components": {
"state_db": {
"path": "state_5.sqlite",
"digest": "sha256:...",
"transaction_sequence": 91842
},
"global_state": {
"path": ".codex-global-state.json",
"digest": "sha256:...",
"generation": 1842
},
"session_index": {
"path": "session_index.jsonl",
"digest": "sha256:...",
"last_sequence": 7712
},
"rollout_registry": {
"count": 791,
"digest": "sha256:..."
}
},
"commit_status": "COMMITTED"
}
A safe write sequence could be:
write temporary file
→ flush file
→ fsync
→ validate parse and schema
→ atomic rename
→ fsync parent directory
→ update checkpoint manifest
The runtime should never replace a rich valid projection with a minimal default merely because startup encountered an incomplete write.
A recovery process could be:
discover candidate states
→ reject incomplete/uncommitted generations
→ validate digests and schemas
→ compare registries
→ detect impossible timestamps
→ reconstruct derived indexes
→ publish recovery report
A structured drift report might look like:
{
"schema_version": "state-reconciliation-report/v0.1",
"checkpoint_id": "checkpoint-20260624-1842",
"status": "DRIFT_DETECTED",
"findings": [
{
"component": ".codex-global-state.json",
"finding": "PROJECTION_INCOMPLETE",
"observed_projects": 1,
"recoverable_projects": 27
},
{
"component": "session_index.jsonl",
"finding": "MISSING_THREAD_REFERENCES",
"count": 675
},
{
"component": "thread timestamp",
"finding": "IMPOSSIBLE_FUTURE_TIME",
"observed": "7026-02-04T18:32:49Z"
}
],
"decision": "REBUILD_DERIVED_PROJECTIONS"
}
Another useful invariant:
«UI indexes and sidebar state should be treated as rebuildable projections, not as the sole source of truth for whether conversations exist.»
For example:
project view says “No chats”
→ projection is stale
→ rebuild index
not:
“No chats”
→ assume conversations were deleted
Timestamp handling should also be evidence-based. A future timestamp should not automatically win conflict resolution.
timestamp > current time + allowed skew
→ INVALID_TIME_EVIDENCE
→ exclude from freshness ordering
Configuration recovery should be version-bound:
{
"config_snapshot": {
"schema_version": 7,
"writer_version": "26.602.4764.0",
"parser_compatibility": [
"26.602.x"
],
"digest": "sha256:..."
}
}
This helps prevent an older or partial writer from restoring a value the installed parser cannot accept.
A deterministic conformance fixture could test:
A supported command such as:
codex doctor --reconcile-state
could generate a redacted report first, then apply only deterministic repairs:
SCAN
→ REPORT
→ BACKUP
→ REPAIR
→ VERIFY
→ COMMIT
Related LS work:
https://github.com/safal207/LS/issues/594
https://github.com/safal207/LS/issues/595
https://github.com/safal207/LS/issues/597
https://github.com/safal207/LS/pull/651
Would a small vendor-neutral "StateCheckpointManifest" and crash-recovery conformance fixture help test atomic persistence, cross-store drift detection, timestamp validation, and deterministic projection rebuilding?
July 14-15 recurrence on 26.707.8479.0: UI hang, abrupt restart, and persistent NUL process cache
This happened again on the same Windows profile with a much newer package:
This recurrence was not caused by a power loss. The Desktop UI became unresponsive while tasks were running and Windows displayed the standard "not responding" flow. While its confirmation prompt had focus, a stray Space/Enter keypress intended for the composer confirmed
End Process. A single accidental keypress therefore terminated the app and stopped the running turns; the tasks had to be resumed manually.Timeline and crash evidence
For the latest occurrence on July 15 (local time, UTC-03:00):
There was therefore an intermediate package activation before the previous root stopped, rather than a simple one-process transition. The old log ended abruptly without a normal shutdown sequence. However, I found no corresponding:
The new process entered the same packaged-app container. This looks like abrupt process termination followed by a quick relaunch, rather than a documented native crash.
Error burst immediately before termination
During the
09:56:00-09:56:56.715portion of the old process log there were 171 lines, including:From
09:52:00until termination there were 320 error-level records, including 227 unknown-conversation records, 87 missing-conversation-state records, and 22 JSON/NUL parse errors. These categories overlap, so their subtotals are not additive. I cannot prove that this error burst caused the UI hang, but it coincided with this occurrence and the log ended immediately afterward. The NUL parse failures themselves have recurred across multiple runs.Persistent all-NUL
chat_processes.jsonI found a concrete persistent corruption that was not included in my original report:
The Desktop app has continued attempting to parse this same invalid file across upgrades and repeatedly logs JSON parse failures. Inspection of the currently packaged JavaScript shows that the reader treats
ENOENTas an empty process-record list. With invalid JSON, parsing fails and the higher-level handler repeatedly logs the failure. The writer recreates the directory/file with a JSON array when it next persists records.This file is a process-association cache, not the durable conversation store. A conservative local repair is therefore to close the app completely and move the all-NUL file to a dated backup, leaving it absent so the implemented
ENOENTfallback yields an empty list; the normal writer can then recreate it. I am preserving the original file for diagnostics.Log database growth and integrity checks
Shortly after the recurrence:
PRAGMA quick_check(1)returnedokfor bothlogs_2.sqliteandstate_5.sqlite. The log database contains diagnostic logs separately from the conversation state database.The important recovery result is that this occurrence did not delete the interrupted conversations:
state_5.sqlitepassedquick_check;.codex-global-state.jsonand its backup both parsed successfully;session_index.jsonlparsed successfully;The tasks were interrupted, but their persisted history remained recoverable. The app did not automatically continue the running turns after relaunch.
One workspace volume was also critically low on free space at the time, so I cannot rule out additional I/O pressure as a contributor to the hang. That does not explain the long-lived all-NUL process cache, and forced termination still needs a deterministic recovery path for active tasks and local state.
What this adds to the original report
The failure mode is broader than physical power loss:
End Processflow can turn that hang into an ungraceful termination;This reinforces the need for atomic writes plus startup validation/quarantine of invalid local state files. A startup check could detect an all-NUL
process_manager/chat_processes.json, preserve it as a diagnostic artifact, rebuild the process cache, and reconcile still-running/interrupted turns from durable conversation state instead of repeatedly parsing the same invalid file.July 27 recurrence on Windows app 26.721.4979.0: repaired pins are overwritten by stale in-memory state
I can reproduce the same crash-safety failure on a substantially newer Windows Store build.
Environment
OpenAI.Codex_26.721.4979.0_x64__2p2nqsd0c76g0Observed behavior
%USERPROFILE%\.codex\.codex-global-state.jsonand.codex-global-state.json.bakparsed successfully, but both contained the same reduced 3-entrypinned-thread-idsarray.state_5.sqlite,session_index.jsonl, and the rollout files. Their content was not deleted; this is a projection/persistence loss.Stronger deterministic evidence
I backed up the files before every repair and performed the following sequence:
.bakwith valid JSON containing all 6 known pinned thread ids..bakback to the old 3-entry set. In the captured run, both files were rewritten at approximately23:21:39local time.This looks like a lost-update/stale-renderer-state bug, not just a torn JSON write. The running renderer/store keeps an older subset, then later persists the entire stale snapshot and overwrites a richer valid generation. The
.bakfile is not an independent recovery source because it is overwritten with the same stale subset in the same update.Expected behavior / suggested invariants
codex doctor --reconcile-state-style recovery path would avoid manual JSON repair.I am not attaching raw databases, logs, full local paths, project names, or thread ids publicly because they may contain private conversation metadata. I can provide redacted field-level diagnostics if a maintainer specifies what is needed.
July 28 recurrence: live project hydration is wrong even when persisted state is healthy
This happened again on the same Windows 11 machine and the same package build:
OpenAI.Codex_26.721.4979.0_x64__2p2nqsd0c76g0The new evidence narrows the failure from persistence corruption to a startup/live-projection problem as well.
Persisted state was already healthy
Immediately after the user reported that pinned/project conversations had disappeared again, I audited the local state before changing it:
.codex-global-state.jsonand.codex-global-state.json.bakparsed successfully.thread-project-assignmentsentries.So, unlike the previous recurrence, the persisted JSON did not need repair.
Live task projection was still wrong
Despite the healthy persisted state, the initial live task-list response returned all 6 pinned threads but reported
projectId: nullfor 3 pinned threads whose on-disk assignments correctly pointed to the same saved local project. The sidebar consequently treated these conversations as missing or outside their project.I then re-issued an idempotent pin mutation (
pinned=true) for those same 3 thread ids. Immediately afterward, the live task list still contained the same 6 pins, but the 3 affected rows now had the correct project id. No disk-level project assignment had changed; the mutation only forced the live model to rehydrate/reconcile the rows.What this suggests
This is not only a torn-write or stale-full-snapshot problem. There also appears to be a startup/live hydration mismatch:
projectId: null;Suggested invariant/test:
thread-project-assignmentsbefore publishing sidebar/task rows.projectId: nullbut durable state has a valid assignment and the thread cwd matches that saved project, reconcile instead of dropping the relationship.This recurrence further supports adding a supported
codex doctor --reconcile-statepath and startup projection validation. I can provide additional redacted counts or field-level diagnostics if maintainers request them.August 4 recurrence after Windows app update: live pins are empty despite healthy persisted state
This issue has recurred again after updating and restarting the Windows desktop app.
Environment
OpenAI.Codex_26.727.6591.0_x64__2p2nqsd0c76g0Deterministic pin evidence
The expected set is 6 pinned local threads.
%USERPROFILE%\.codex\.codex-global-state.jsonand its.bakparse successfully.pinned-thread-idsarray.pinCount: 0and no pinned rows.pinned=truefor each of the same 6 known thread ids. Every mutation returned success.pinCount: 0.This is stronger evidence of a live hydration/projection failure: a successful mutation is acknowledged, but the live store remains empty even while both durable JSON generations contain the complete set.
Project/session audit
A redacted local audit found:
state_5.sqlite: 395 thread rows, 394 active, 1 archived;PRAGMA quick_checksucceeds.thread-project-assignments: 110 entries across 17 saved local projects.state_5.sqliteorsession_index.jsonl.external_agent_session_imports.jsonas previously imported external-agent sessions.No raw databases, local paths, project names, titles, or thread ids are being posted publicly.
Why this matters
The app now has at least three mutually inconsistent views of the same state:
The current update/restart path therefore does not merely lose a write. It can fail to hydrate the live model from valid durable state, acknowledge idempotent mutations without reflecting them, and leave the external-import ledger claiming sessions were imported after their catalog rows disappeared.
Requested fix
Please add a startup reconciliation invariant/test for this exact case:
set pinned=trueoperation must be observable in a subsequent list call.external_agent_session_imports.jsonagainststate_5.sqliteandsession_index.jsonl; if an import record exists but its thread row is missing and the source file still exists, re-import it automatically.projectId: nullwhen a valid durable assignment exists and cwd matches the saved project.codex doctor --reconcile-statecommand that repairs pins, project assignments, session indexes, and stale import-ledger records without manual SQLite/JSON surgery.This has now happened repeatedly across multiple Windows desktop builds and is triggered by ordinary app updates/restarts as well as crashes. It is causing persistent, user-visible disappearance of pinned and project conversations.
August 4 Windows reproduction on 26.727.6591.0: healthy local history remains hidden until threads are pinned
I encountered a project-sidebar history disappearance on the current Windows Store build:
This report is sanitized. Project names, local paths, username, prompts, and thread IDs are omitted.
User-visible behavior
Evidence that the data was intact
A Codex assistant inspected the local state and confirmed that:
state_5.sqlitecontained the matching active rows with valid rollout paths..codex-global-state.jsonretained the saved projects and thread-to-project assignments.codex doctorreported healthy state databases and agreement between the rollout files and database inventory.This established that the conversations had not been deleted.
Recovery investigation performed by Codex
After searching the public
openai/codexGitHub issues, the Codex assistant identified #25500, #25463, and #26990 as closely matching reports.With the user’s approval, Codex then tested the recovery methods suggested by those reports:
OKturn.Codex also identified a compatibility difference: older affected rows used
model_provider = openai, while newly created Desktop rows usedmodel_provider = chatgpt-http. Updating this metadata made the live thread-list path recognize the older rows.However, none of these actions restored the conversations in the Projects sidebar. The projects continued to show No chats.
Codex then tested the pinning workaround reported on GitHub by setting
pinned=truefor the same 13 thread IDs.All 13 conversations immediately became visible in Codex Desktop.
What this narrows down
The investigation indicates a Desktop live-hydration or sidebar-projection failure rather than data loss:
Suggested regression test
pinned=true.model_provider = openairows alongside currentchatgpt-httprows.Pinning is currently an effective workaround on this machine, but users should not need to pin every historical conversation to access valid project history.
August 10 recurrence on 26.803.5235.0: ordinary reopen republishes stale sidebar state after successful disk repair
This is another recurrence on the current Windows desktop package:
I am reporting this as a serious reliability issue because it has now reproduced across multiple Windows builds, including
26.727.6591.0,26.730.7989.0,26.730.8199.0, and26.803.5235.0.Deterministic sequence observed
Current redacted local evidence
After live recovery:
Several heavily used projects retain stable active counts, including 33, 14, 14, 10, and 6 threads respectively. This rules out a uniform database wipe during this recurrence.
Stale in-memory overwrite evidence
On the immediately preceding recurrence with the same build family, the running desktop process rewrote a repaired JSON generation from 6 pins back to 3 and reinserted 10 assignment ids that had already been superseded by successful reimports. SQLite continued to report all 6 pins.
After the process exited, the repair pass again observed
beforePinCount: 3, removed the same 10 stale ids, and restoredafterPinCount: 6.This strongly suggests a stale in-memory snapshot or renderer/main-process projection is being persisted over a richer, valid generation. The problem is not limited to crash-unsafe writes: ordinary launch/reopen can publish or persist stale sidebar state after a successful repair.
Severity and impact
Requested engineering changes
codex doctor --reconcile-stateoperation for pins, project membership, stale assignments, and session indexes.No private prompts, thread ids, project names, usernames, or raw databases are included here. I can provide further redacted field-level diagnostics if a maintainer requests them.
I hit what appears to be the same failure mode after repeated abrupt Windows shutdowns, and I was able to fully recover the local projects including the original project/thread grouping without modifying the conversation contents.
What was actually lost
The conversations themselves were still intact.
In my case:
state_5.sqlitestill contained 313 threadscwdWhat had been reset was the project/index state in:
%USERPROFILE%\.codex\.codex-global-state.jsonImmediately before recovery, the state had effectively collapsed to:
After reconstruction:
Important schema difference
In this current Windows build, I did not find:
thread-workspace-root-hintsbefore recovery, immediately after recovery, or after restarting Codex.
The project/thread mapping used by this installation was instead stored primarily in:
local-projectsproject-orderthread-project-assignmentsthread-writable-rootsprojectless-thread-idsSo recovery logic should not assume that
thread-workspace-root-hintsexists across app versions.Recovery approach
With Codex fully closed:
.codex-global-state.jsonand its.bak.state_5.sqliteusing SQLite's backup API.PROJECT_CONTEXT.md.\\?\where present.cwdto:local-projectsproject-orderthread-project-assignmentsthread-writable-rootsprojectless-thread-idsstate_5.sqlite, session files, chat titles, chat contents, or archive status.fsync, then atomically replaced the original withos.replace().For local project IDs, I generated deterministic UUIDv5 IDs from the normalized absolute project path, while preserving the ID of the existing workspace.
Result
The full local project organization was restored successfully.
This suggests that, at least in some current Windows builds, a crash/power-loss recovery feature could potentially reconstruct missing project metadata automatically from:
state_5.sqlitethread IDs /cwdrather than treating missing project state as deleted conversations.
I would strongly prefer an official repair/reindex command rather than editing internal state manually.
Safety note
I am not publishing my raw
.codex-global-state.json, SQLite databases, sessions, logs, or the exact recovery script because they contain local paths/project information and may contain private user data.The recovery method above depends on undocumented internal state and may be version-specific. It should be considered an emergency recovery procedure, not a supported general-purpose fix.
If useful to maintainers, I can produce a sanitized recovery script with configurable
--codex-home,--workspace-root,--projects-root,--aliases-file,--dry-run, and--output-reportparameters.Following up with an executable artifact rather than another design sketch.
The failure classes reported in this thread are now encoded as a small vendor-neutral conformance fixture in LS:
ls-conformance/state_projection_recovery/The fixture keeps these surfaces separate:
It currently covers eight deterministic vectors:
thread-workspace-root-hints;\\?\verbatim path equivalence;The important adjustment from the newer reproductions here is that recovery does capability/schema discovery first; it does not assume one global-state key set across builds.
The core conformance invariant is:
The dedicated fixture CI is passing, including generation blocking, path normalization, content-preservation and a redaction-safe reconciliation report.
This is not a Codex repair script and does not touch real user state; the goal is to provide a portable regression oracle for the failure mode described in this issue. If a native Codex recovery/reindex implementation lands, I’d be happy to adapt the vectors to its preferred interfaces.
Severe recurrence on Windows — 2026-08-14
This serious persistence bug has reproduced again on
OpenAI.Codex_26.803.10989.0_x64__2p2nqsd0c76g0.After an ordinary desktop update/reopen—and again after a client crash—pinned conversations disappeared and conversations from multiple unrelated projects no longer appeared under their projects. The database integrity check itself passed, so this is consistent with a migration/reconciliation/persistence failure rather than ordinary database corruption.
A local recovery was able to restore missing imported conversations, rebuild project membership from live thread metadata, and restore the required pinned set. However, the same failure has repeatedly returned after later updates or restarts.
This pattern has now been observed across at least these Windows desktop builds:
Please treat this as a high-severity persistent-state/data-loss issue. The desktop app needs:
codex doctor --reconcile-state;A user-space watcher is not a durable workaround because it can be terminated by the same update, crash, or reboot that triggers the loss. The repair needs to be native and run automatically on every startup.
This recurrence adds one important discriminator to the failure model: abrupt power loss is no longer a required trigger. An ordinary update/reopen can produce the same loss of pins/project projection while the canonical thread database remains internally valid.
That suggests the regression contract should explicitly separate canonical conversation state from derived UI/project projection:
A useful invariant for a native fix/test would be:
The LS conformance fixture I linked earlier can model this recurrence as a distinct vector rather than treating it as another power-loss case:
ordinary_update_reopen_preserves_projectionwith pre/post assertions over at least:
The key property is monotonic preservation of recoverable membership across startup reconciliation, plus generation/CAS rejection of any stale or incomplete writer. That seems to match the new evidence more closely than a generic SQLite-corruption test.
Follow-up with the executable vector for the new trigger class rather than another design note.
The 2026-08-14 recurrence showed that abrupt power loss is not required: an ordinary desktop update/reopen can be enough to lose project membership and pinned conversations while durable thread evidence remains intact.
I encoded that transition as a new vendor-neutral LS conformance vector:
b7fe591c85eea80a3fb0062d04cf261407387b1eordinary_update_reopen_preserves_projectionThe transition model is deliberately stricter than the earlier recovery-only fixture:
The frozen recurrence vector gives the candidate a newer generation but removes two still-supported project memberships and two pins. With no explicit user mutation authorizing that reduction, the oracle returns
BLOCK_REGRESSIVE_PROJECTIONand keeps the trusted generation authoritative.I also added negative controls: a complete newer projection is accepted, an explicit user-authorized reduction is accepted, and a stale startup writer is blocked.
One important distinction in the fixture: project membership may be reconstructable from durable thread metadata, but pins are user-authored state. The oracle therefore preserves pins rather than attempting to synthesize them from cwd/path evidence.
All deterministic tests, both redacted reports, and artifact upload are green in the linked run. As before, this is synthetic conformance data and does not read or modify real Codex state.
Following up with the merged executable artifact for the 2026-08-14 update/reopen recurrence.
The transition-level conformance vector is now merged in
safal207/LS#932at squash commitfa7e3aba4ff9154856fa7d27c92f702137819ac1.It now exercises the startup/reconciliation boundary directly:
The CI/logging boundary was also hardened after security review: detailed synthetic case reports stay in-process, while the published transition artifact contains only aggregate counts over fixed verdict classes.
Final validation on the merged head included the dedicated state-projection conformance workflow plus the repository security pipeline: hardening tests, quality gate, vulnerability audit, SBOM generation, dependency review and CodeQL all passed. GitHub Advanced Security reports no new alerts in code changed by PR #932.
This remains a vendor-neutral regression oracle, not a Codex repair script. If a native startup reconciler or a supported recovery command such as
codex doctor --reconcile-statelands, these vectors can be adapted to that interface.One architectural direction that may reduce the number of independent recovery paths here: treat the JSON/sidebar state as a rebuildable projection, not a second authority.
The failure pattern is especially hard to recover when several stores can each look individually valid but describe different generations of state. A small generation/commit marker across the durable stores would make that detectable.
For example:
On startup:
I would also distinguish
missing,stale, andcorruptrather than mapping all three to “initialize defaults.” A stale-but-readable file is exactly the dangerous case here: it can silently look legitimate while dropping projects/pins.That gives the UI a useful invariant: if the authoritative thread records still exist, losing a cache/projection may affect startup time, but should not affect whether a project appears to exist. The projection becomes disposable and recoverable rather than load-bearing user data.
I’m testing Codex Rescue
0.1.0a3against crash/power-loss recovery cases. Your report is useful because the global/UI/SQLite state drifted badly after abrupt shutdown, while many underlying rollout files remained recoverable.Rescue works from local rollout data, does not modify Codex SQLite/global state, and fails closed when it cannot prove a safe continuation. It does not repair
.codex-global-state.json, timestamps, or config migration.If you still have one affected pre-repair session, would you be willing to try:
If it identifies the right rollout, sanitized
salvage --fork/verifyoutput would help validate the rollout-level recovery boundary. Please don’t post raw rollouts, SQLite DBs, config/auth files, prompts, credentials, or private paths.https://github.com/shleder/codex-rescue