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.
7 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.