Repository navigation
Codex Desktop project chat history disappears after update due to WSL cwd/path migration mismatch #24364
Description
Summary
Codex Desktop can show an empty project chat history even though local session files and state DB rows still exist. In this case, every project sidebar appeared empty except the current chat. The local repair showed two related migration/path compatibility problems after a Codex Desktop/app-server update:
state_5.sqliteandlogs_2.sqlitecontained_sqlx_migrationschecksum rows from an older build. A freshcodex app-serverfrom the installed binary refused to initialize with:
failed to initialize sqlite state db: failed to initialize state runtime at <CODEX_HOME>: migration 1 was previously applied but has been modified
- Older sessions had
cwdvalues persisted as Windows paths such as:
C:\Users\<user>\Documents\codex-projects\surfaceguru
When queried by the current WSL app-server, thread/list treated those Windows paths as relative strings and produced unusable cwd values like:
/mnt/c/Users/<user>/Documents/codex-projects/surfaceguru/C:\Users\<user>\Documents\codex-projects\surfaceguru
As a result, project-scoped thread/list queries returned data: [] even though matching rows and rollout files existed.
Environment
- Product: Codex Desktop
- Windows package observed:
OpenAI.Codex_26.513.4821.0_x64__2p2nqsd0c76g0 - App-server / CLI:
codex-cli 0.131.0-alpha.9 - App-server command:
codex app-server --analytics-default-enabled - WSL: Ubuntu 24.04
CODEX_HOME: Windows user profile.codex, exposed in WSL as/mnt/c/Users/<user>/.codex- Desktop app-server env included
CODEX_INTERNAL_ORIGINATOR_OVERRIDE=Codex Desktop
User-visible symptom
- Project chat sidebar showed only the current chat.
- Previous chats under multiple projects were missing from the UI.
- Local data was not actually gone:
- 47 local session
.jsonlfiles existed. session_index.jsonlexisted.state_5.sqlitecontained thread rows.
- 47 local session
Local diagnostic evidence
Direct app-server probe before migration checksum repair:
$ codex app-server --analytics-default-enabled
failed to initialize sqlite state db: failed to initialize state runtime at /mnt/c/Users/<user>/.codex: migration 1 was previously applied but has been modified
After matching _sqlx_migrations checksums against a clean state created by the same installed codex-cli 0.131.0-alpha.9, app-server initialized successfully.
Then thread/list exposed the path mismatch. Before cwd repair, querying the current project returned no history:
{"id":2,"method":"thread/list","params":{"archived":false,"cwd":"C:\\Users\\<user>\\Documents\\codex-projects\\surfaceguru","limit":20,"useStateDbOnly":true,"sourceKinds":["vscode","cli","appServer","unknown"]}}Response:
{"id":2,"result":{"data":[],"nextCursor":null,"backwardsCursor":null}}Unfiltered results contained malformed cwd values:
/mnt/c/Users/<user>/Documents/codex-projects/surfaceguru/C:\Users\<user>\Documents\codex-projects\surfaceguru
After converting persisted cwd values in both state_5.sqlite and session JSONL session_meta / turn_context payloads from Windows paths to WSL paths, project-scoped thread/list returned the expected chats:
surface project: 4
network project: 4
burbflix project: 31
burbflix-iptv project: 4
burbfinity project: 1
playground: 1
Example successful query after repair:
{"id":2,"method":"thread/list","params":{"archived":false,"cwd":"/mnt/c/Users/<user>/Documents/codex-projects/surfaceguru","limit":20,"useStateDbOnly":true,"sourceKinds":["vscode","cli","exec","appServer","subAgent","subAgentReview","subAgentCompact","subAgentThreadSpawn","subAgentOther","unknown"]}}Response contained the expected 4 project threads.
Expected behavior
Codex Desktop should preserve and display existing project chat history across updates and across Windows/WSL execution mode changes. Older rollout files containing Windows-style cwd values should still match project filters, or should be migrated automatically.
Actual behavior
Older project chats became invisible in the sidebar. The app-server could read the files but project filtering failed because persisted Windows paths were interpreted relative to the current WSL cwd instead of normalized/canonicalized.
Suggested fix areas
- Add a startup/read-repair migration for persisted thread
cwdvalues that canonicalizes Windows paths when running under WSL. - Normalize both the query-side cwd filter and stored cwd before exact matching in
thread/list. - Avoid treating
C:\...as a relative Unix path under WSL. - Add defensive handling when
_sqlx_migrationschecksum metadata changes across packaged Desktop/app-server builds, especially forstate_5.sqliteandlogs_2.sqlite. - Add a regression test with old Windows-style rollout
cwdfields and WSL-style project cwd filters.
Privacy note
This report intentionally omits private chat content and uses redacted paths. The original local data contained normal project chat history; the important failure was path/state classification, not missing files.
Activity
github-actions commentedon May 24, 2026
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
yui-stingray commentedon May 24, 2026
This looks consistent with a cwd normalization mismatch in the thread listing path.
thread/listnormalizes cwd filters withAbsolutePathBuf::relative_to_current_dir(...), so a legacy Windows-style cwd can be interpreted relative to the WSL cwd. WhenuseStateDbOnlyis used, the lookup then goes directly to exactthreads.cwdmatching and skips the scan-and-repair path that would normalize/backfill existing rows. That could make older sessions remain invisible until they are rewritten or repaired.huajiexiewenfeng commentedon May 31, 2026
This looks very close to the local recovery case I ran into, especially the path/cwd migration angle.
I collected my recovery workflow here:
https://github.com/huajiexiewenfeng/codex-session-recovery
It is an unofficial workaround, not an upstream fix. The workflow dry-runs first, checks
session_index.jsonl,.codex-global-state.json, SQLitethreads.cwd, exact UIcwdmatching, and Windows/WSL-style path mismatches such as\\?\prefixes. It backs up files before writing and verifies the recovery afterward.The part that may be relevant here is the
cwd_exact_match_riskcheck: in some cases the data is still present locally, but the Desktop UI cannot find it because the stored threadcwdand the visible project root do not match as exact strings.loertel commentedon Jul 15, 2026
Confirmed reverse-direction case: WSL → native Windows
I reproduced the same class of failure in the opposite migration direction and completed a successful local recovery.
Environment
26.707.9981.00.139.0CODEX_HOMESymptom
session_index.jsonl,.codex-global-state.json, and SQLite thread rows still existed.\\wsl$\<distro>\...and\\wsl.localhost\<distro>\...had been saved.Historical session metadata contained paths such as:
The native Windows thread catalog exposed unusable equivalents such as:
while the visible Desktop projects used:
Important native-Windows detail
For JSONL metadata and Desktop project state, normal native paths were correct:
However, storing those same non-extended strings in
state_5.sqlite.threads.cwdwas not sufficient. A project-scoped request withuseStateDbOnly: truestill returned an empty result.The state DB had to use the native Windows extended forms that the query-side path normalization compares against:
After converting
threads.cwdto those forms, the same project-scopedthread/listrequests returned the expected threads immediately.Recovery scope
With Codex fully stopped, the recovery updated these sources together:
sessions/**/*.jsonlandarchived_sessions/**/*.jsonlpayload.cwdinsession_meta,turn_context, and other cwd-bearing recordsstate_5.sqlitethreads.cwd, using native Windows extended pathssqlite/codex-dev.dblocal_thread_catalog.cwd, using normal visible paths.codex-global-state.jsonand its backupwsl$/wsl.localhostproject entriesValidation after restart
/home/...,/mnt/<drive>/...,C:\home\..., or inconsistent\\?\...JSONL cwd values remained.PRAGMA integrity_checkreturnedokfor both SQLite databases.This strongly suggests the upstream fix should canonicalize both stored and query-side cwd values symmetrically in both migration directions, and migrate JSONL, state DB, catalog DB, and Desktop project state as one coordinated operation.
I also have a sanitized, dry-run-first reference migration script that creates per-file backups and validates JSONL/SQLite before reporting success. It contains no local usernames, project names, thread IDs, titles, or private paths.
Sanitized dry-run-first reference migration script
TeaShaman-cyber commentedon Jul 22, 2026
Additional current-build datapoint (2026-07-22):\n\n- Codex Desktop Windows package: 26.715.9757.0\n- codex-cli: 0.144.5\n- app-server runs in Ubuntu 24.04 WSL with CODEX_HOME on the mounted Windows profile.\n- The thread row in state_5.sqlite keeps the correct canonical Windows cwd (\?\C:\Users\\...\).\n- Codex core turn logs also use the correct Windows cwd.\n- However, an emitted turn_context.cwd / workspace root was malformed by joining an app resources directory with the Windows path:\n /mnt/c/Program Files/WindowsApps/OpenAI.Codex_26.715.4045.0.../app/resources/C:\Users\\Documents\Codex\n- The currently installed package is 26.715.9757.0, so the malformed context also retained an older package-version path.\n- In the same affected project, a valid repo-local .codex/hooks.json disappeared from the Hooks UI; the runtime later logged a legacy after-agent hook failure with Windows os error 206.\n\nThis looks like split path normalization across the thread registry, turn runtime, and workspace/hook discovery layers. Relative hook commands avoid the hardcoded project path but do not repair the malformed workspace root itself.