Skip to content

[Windows] NUL-corrupted state wipes projects and backup #38757

Open

Description

@dovvnloading

What version of the Codex App are you using (From “About Codex” dialog)?

26.810.4967.0

What subscription do you have?

Pro

What platform is your computer?

Microsoft Windows NT 10.0.26200.0 x64

What issue are you seeing?

All existing projects disappeared from the Codex App after startup.

At 07:18:45 on 2026-08-15, Codex loaded a NUL-filled .codex-global-state.json as empty state. It then saved the replacement project registry and copied it to .bak, overwriting the recovery backup without warning.

Existing chat rows and workspace folders remained on disk, but the project list and thread-to-project mappings were gone. Creating one test project produced a registry containing only that project; none of the previous chats were reattached.

This is persistent metadata loss, not a sidebar display or cache problem.

What steps can reproduce the bug?

  1. Start with a Codex profile containing multiple projects and project-linked chats.
  2. Close Codex, leaving the thread database intact.
  3. Make .codex-global-state.json invalid by filling it with NUL bytes.
  4. Launch Codex.
  5. Codex opens without an error and shows an empty Projects list.
  6. Create one test project and restart.
  7. Only the test project remains. Previous mappings are absent, and .bak contains the replacement state instead of the last known-good registry.

Observed result: the registry changed from 8 projects / 65 assignments to 1 project / 0 assignments while the thread database retained approximately 1,070 rows.

What is the expected behavior?

Codex must treat an invalid global-state file as a recovery event, not as a valid empty registry.

It must stop automatic writeback, preserve the last known-good backup, warn the user, and restore or rebuild project mappings from durable records. It must never copy unvalidated replacement state over the recovery backup.

Additional information

Evidence:

  • Codex App: 26.810.4967.0
  • Windows: 10.0.26200.0 x64
  • Last usable snapshot: 8 projects, 65 assignments
  • Current registry: 1 test project, 0 assignments
  • Thread database: approximately 1,070 rows
  • Failure timestamp: 2026-08-15 07:18:45 local time
  • Troubleshooting began afterward at 07:19:35
  • No task, prompt, project-name, or conversation content is included

GitHub flags #37212 as related. This incident additionally records NUL corruption and overwrite of the recovery backup.

Activity

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

    @github-actions
    Contributor

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

    Powered by Codex Action

  4. kovachinfo commented on Sep 7, 2026

    @kovachinfo

    I experienced a similar issue on Windows on September 7, 2026.

    App version: 26.901.6511.0
    Codex CLI helper: 0.153.4

    After reboot, the app launched successfully, but onboarding appeared again and all local projects disappeared from the sidebar. Existing chats and workspace folders remained available.

    Desktop logs recorded:
    “[global-state] Failed to load global state”
    “Unexpected token '\u0000' ... is not valid JSON”

    Shortly afterward, the logs reported:
    “Local app-server project migration completed projectCount=15”

    However, the sidebar still showed no local projects:

    • global-state JSON contained an empty local-projects object.
    • state_5.sqlite retained 15 projects, 15 project roots and 190 threads.
    • All threads.project_id values were NULL.

    Recovery:
    With the app closed, we rebuilt the JSON project list from the CURRENT SQLite records, without restoring an older snapshot or modifying SQLite. We also reconstructed 169 task assignments using unique matching workspace paths. After restarting, all 15 projects became visible again.

    Separately, Windows Controlled Folder Access blocked codex-windows-sandbox-setup.exe, causing “setup refresh had errors” when executing local commands. Allowing that executable restored command execution. We have no evidence that Defender caused the global-state corruption.

    The cause of the NUL bytes remains unknown. The original corrupt state was no longer available by the time diagnostics were collected.

    This may help investigate why surviving SQLite projects are not restored to the sidebar after global-state corruption.

  5. tengweid commented on Sep 10, 2026

    @tengweid

    Urgent escalation: another Windows incident with conversation access loss and interrupted project work

    Please prioritize this as a serious data-integrity and work-continuity incident. The affected user explicitly reports that this has caused serious consequences, including lost conversations and interrupted project progress/work incidents, and requests a prompt fix and a response from the Codex team.

    Environment and incident window

    • Windows 11 Pro, version 10.0.26200, x64.
    • Desktop package: OpenAI.Codex_26.903.8094.0_x64 (version obtained from the installed package path).
    • Bundled backend: codex-cli 0.153.4.
    • Incident investigation and recovery: September 9–10, 2026, Asia/Shanghai (UTC+8).

    New evidence from this installation

    1. A September 6 state snapshot retained 10 original local projects and 100 explicit thread-to-project assignments. On September 9, the app exposed only two newly present local projects; many existing conversations had no project association.
    2. On September 10, .codex-global-state.json contained "local-projects": {}, with no thread assignment map, while the SQLite project records and many existing thread rows/associations still existed.
    3. The persisted migration marker read projectsMigrated: true and threadAssignmentsMigrated: false.
    4. A separately preserved config.toml.corrupted.bak was inspected as bytes, without exposing its contents:
      file size:         5092 bytes
      NUL bytes:         5092
      unique byte count: 1
      
      This is direct evidence of configuration corruption on the same machine. It may relate to Desktop: config.toml zero-filled to NUL bytes after ungraceful shutdown — non-atomic write on Windows loses entire file content #26421, but it does not by itself establish what caused the project registry loss.
    5. Recovery required backups, reconstruction from the historical registry and surviving database records, restoration of missing associations, and a complete desktop stop/restart. The resulting state contained 12 local projects (10 original plus 2 later projects) and 182 thread assignments, including 11 newly filled database associations. Post-restart checks and the app's own project/thread listing tools confirmed restored project grouping.

    Impact and limits of the diagnosis

    • User-reported impact: conversation loss, project-progress interruption, repeated recovery work, and serious disruption to ongoing work.
    • Independently verified: project metadata/association loss and conversations becoming detached from their original projects. Surviving data could be recovered.
    • We have not established whether every reported missing conversation was permanently deleted, nor audited all message content for completeness. Please investigate the broader history-loss risk.
    • There is no deterministic reproduction of the original triggering event. No causal claim is being made about power loss, an update, or non-atomic writes.
    • During recovery, editing state while the app was running was overwritten by its in-memory state. Those recovery attempts and deliberate restarts happened after the original incident; they are not evidence of its original cause. Recovery does not establish a permanent product fix.

    Requested action

    Please:

    1. Urgently triage this with the Windows desktop persistence/history owners and assess the scope of affected users.
    2. Preserve and recover the last valid project, conversation and settings metadata instead of silently replacing invalid or unavailable state with an empty registry.
    3. Investigate configuration durability, backup preservation, project-assignment migration and reconciliation between the desktop registry and SQLite records.
    4. Provide a supported, non-destructive recovery procedure and a fix that survives normal use, updates and restarts.
    5. Acknowledge this escalation and provide the investigation status, mitigation and expected fix timeline when available.

    Potentially related: #26421 (NUL-filled config) and #41874 (history loss/incomplete project-assignment migration). Please link or consolidate these reports as appropriate; a common root cause has not been confirmed.

    This report is intentionally redacted: no local username, project names, account identifiers, credentials, raw databases or conversation transcripts are included. Sanitized recovery evidence has been retained locally.

  6. ayaanexperimental-bit commented on Sep 14, 2026

    @ayaanexperimental-bit

    Windows desktop loses project registry after primary and backup state fail parsing

    Environment

    • Windows, packaged Codex desktop 26.901.4073.0.
    • No usernames, task content, project names, credentials, or full session logs included.

    Observed failure

    At 2026-09-13T12:04:49.433Z and 12:04:49.452Z, desktop startup logged:

    [global-state] Failed to load global state
    Unexpected token '\u0000' ... is not valid JSON
    

    The two call sites correspond to the primary .codex-global-state.json and its .bak fallback. Both parse failures return null; the outer loader then returns an empty Map.

    The same startup subsequently logged:

    [host-app-server-projects] Local app-server project migration completed projectCount=4
    

    Despite the four surviving database projects, the sidebar exposed no local projects. The local-projects cache was empty. Existing task records survived.

    Reproduction already performed safely

    The installed bundle's actual uE/dE loader functions were executed unmodified with an in-memory filesystem boundary. No live files were corrupted or modified.

    1. Valid primary JSON: state retained.
    2. NUL-filled primary plus valid backup: backup recovered.
    3. NUL-filled primary and backup: two parse failures, then empty state.

    All three characterization cases passed. This reproduces the empty-state fallback, not the origin of file corruption or every historical disappearance.

    Bundle: .vite/build/window-all-closed-KNH8jchn.js.
    Loader SHA-256: a490ada7d97ab3516d0a8ebe4e90e90211dcfb6884a4973ccbb391932bcd6710.

    Expected behavior / requested remediation

    • Preserve corrupt inputs for diagnosis rather than silently replacing recoverable metadata with defaults.
    • Retain an independently recoverable, validated last-known-good snapshot.
    • Audit Windows persistence durability: the observed writer performs temp-file write/rename and then repeats the same payload for .bak, without explicit flush in the inspected functions.
    • Reconcile surviving server-side projects with the desktop cache, while preserving explicit projectless tasks and exact project assignments. Do not infer arbitrary membership from directory ancestry.
    • Add fault-injection coverage for corrupt primary plus corrupt backup, interrupted saves, and database/cache divergence.

    Recovery and uncertainty

    A backed-up, offline restoration of the original four-project registry and 18 exact task assignments made local projects visible again after startup. This is recovery, not a shipped prevention fix.

    The producer of the NUL bytes remains unknown. An unclean Windows shutdown exists in system history, but causality has not been established. No claim of a confirmed disk failure is made.

  7. lovasoa commented on Oct 2, 2026

    @lovasoa

    Linux/macOS workaround: fully quit ChatGPT/Codex, then paste this into a terminal and reopen the app afterward

    This rebuilds the desktop project registry from surviving state_5.sqlite records. It saves the current settings first, preserves existing assignments and explicit projectless chats, and fills missing assignments only from existing database membership or an exact, unique project-root match. It does not edit SQLite. Remote-only projects cannot be reconstructed from the local database. This is a workaround, not a fix for the original corruption; the shorter command was checked on an isolated database fixture.

    (
    set -eu; umask 077
    pgrep -x 'ChatGPT|Codex|codex' >/dev/null && { echo 'Quit ChatGPT/Codex first.' >&2; exit 1; }
    cd "${CODEX_HOME:-$HOME/.codex}"
    b=$(mktemp -d project-recovery.XXXXXX)
    for f in .codex-global-state.json{,.bak}; do [ ! -e "$f" ] || cp "$f" "$b/"; done
    sqlite3 -readonly state_5.sqlite >"$b/new.json" <<'SQL'
    .bail on
    WITH
    s(j) AS (SELECT CASE WHEN json_valid(readfile('.codex-global-state.json'))
     THEN CAST(readfile('.codex-global-state.json') AS TEXT) ELSE '{}' END),
    h(k) AS (SELECT 'local:'||substr(file,1,length(file)-15) FROM pragma_database_list WHERE name='main'),
    p AS (SELECT p.*,coalesce(
     (SELECT key FROM s,h,json_each(j,'$."app-server-project-id-by-legacy-project-id-by-host".'||json_quote(k)) WHERE value=p.id),
     (SELECT key FROM project_idempotency_keys WHERE project_id=p.id LIMIT 1),p.id) legacy FROM projects p),
    r(j) AS (SELECT json_group_object(legacy,json_object('id',legacy,'name',name,
     'rootPaths',json((SELECT json_group_array(path) FROM
     (SELECT path FROM project_roots WHERE project_id=p.id ORDER BY position))),
     'createdAt',created_at_ms,'updatedAt',updated_at_ms)) FROM p),
    a(j) AS (SELECT json_group_object(t.id,json_object('projectKind','local','projectId',
     coalesce((SELECT legacy FROM p WHERE p.id=t.project_id),
     (SELECT p.legacy FROM p JOIN project_roots r ON r.project_id=p.id WHERE r.path=t.cwd))))
     FROM threads t,s WHERE source NOT LIKE '%subagent%'
     AND t.id NOT IN (SELECT value FROM json_each(s.j,'$."projectless-thread-ids"'))
     AND (t.project_id IN (SELECT id FROM p) OR
     (SELECT count(DISTINCT project_id) FROM project_roots WHERE path=t.cwd)=1)),
    u(j) AS (SELECT json_set(s.j,
     '$."local-projects"',json_patch(r.j,coalesce(json_extract(s.j,'$."local-projects"'),'{}')),
     '$."thread-project-assignments"',json_patch(a.j,coalesce(json_extract(s.j,'$."thread-project-assignments"'),'{}')),
     '$."app-server-project-id-by-legacy-project-id-by-host".'||json_quote(h.k),
     json((SELECT json_group_object(legacy,id) FROM p))) FROM s,r,a,h)
    SELECT json_set(u.j,'$."app-server-projects-migration-by-host".'||json_quote(h.k),
     json_object('version',1,'projectsMigrated',json('true'),'threadAssignmentsMigrated',json('false'),
     'threadAssignmentsReadMigrated',json('false'),'pendingThreadAssignmentIds',
     json((SELECT json_group_array(key) FROM json_each(u.j,'$."thread-project-assignments"')))))
    FROM u,h WHERE EXISTS (SELECT 1 FROM p);
    SQL
    [ -s "$b/new.json" ] || { echo 'No surviving projects; nothing changed.' >&2; exit 1; }
    cp "$b/new.json" .codex-global-state.json.bak
    mv "$b/new.json" .codex-global-state.json
    printf 'Reopen the app. Original settings: %s/%s\n' "$PWD" "$b"
    )
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