Repository navigation
[Windows] Archiving fails with os error 2 when rollout paths use the \\?\ prefix; external path normalization is ineffective #39209
Copy link
Copy link
Closed
Labels
appIssues related to the Codex desktop appIssues related to the Codex desktop appbugSomething isn't workingSomething isn't workingsessionIssues involving session (thread) management, resuming, forking, naming, archivingIssues involving session (thread) management, resuming, forking, naming, archivingwindows-osIssues related to Codex on Windows systemsIssues related to Codex on Windows systems
Description
Summary
On Windows, Codex Desktop cannot archive local conversations when the stored rollout path uses the Windows extended-length prefix \\?\. The archive request fails with a thread-store os error 2 even though the rollout file exists on disk.
Environment
- Product: Codex Desktop (Microsoft Store / WindowsApps install)
- App package:
OpenAI.Codex_26.814.5167.0_x64__2p2nqsd0c76g0 - Core (app-server):
codex 26.814.41407 - OS: Windows 11 x64, NTFS
- System locale: zh-CN (error text appears as
系统找不到指定的文件) - Threads: local project threads created through the normal desktop workflow
Actual behavior
- Clicking Archive shuts down the active thread instance, then returns:
failed to archive session: thread-store internal error: failed to archive thread: The system cannot find the file specified. (os error 2) - The conversation stays visible and
state_5.sqlite.threads.archivedremains0. - The referenced rollout
.jsonlexists on disk, and thearchived_sessionsdirectory exists.
Root-cause evidence
state_5.sqlite(threads.rollout_path) contains a mix of path forms:- Failing unarchived threads:
\\?\C:\Users\<user>\.codex\sessions\... - Previously archived threads: plain
C:\Users\<user>\.codex\sessions\...(these archive successfully)
- Failing unarchived threads:
- The extended form is actively re-persisted by the running app, not a one-time corruption:
- An external daemon strips
\\?\fromstate_5.sqliteevery ~3 s. - The running app writes the extended form back within ~16 s for the active/resumed thread.
- Logs show:
codex_rollout::recorder: Resuming rollout from "\\?\C:\Users\<user>\.codex\sessions\...jsonl".
- An external daemon strips
- OS-level file moves are not the problem:
os.renamesucceeds for all four combinations (\\?\→plain, plain→plain,\\?\→\\?\, plain→\\?\) on the same files. The failure is in Codex's path comparison/construction logic, not NTFS. - Threads created during this app run are stored with the extended form; older threads keep plain paths until they are resumed, after which the extended form returns.
Reproduction
- Windows Codex Desktop 26.814.5167.0, local project with existing conversations.
- Open a conversation whose
state_5.sqliterollout_pathuses\\?\C:\.... - Archive it from the conversation menu.
- Observe
os error 2; the thread remains unarchived.
Attempted workarounds and their effectiveness
- External daemon rewriting
state_5.sqliteto strip\\?\fromrollout_path/cwdevery ~3 s.- Effectiveness: not effective while the app is running. The app re-persists the extended form within ~16 s for active/resumed threads. It only prevents the DB from accumulating prefixed rows.
- Fully quit Codex → normalize the DB while stopped → restart → archive before opening/resuming the thread.
- Effectiveness: temporarily works for threads that are already affected (their rows are plain at startup and they archive successfully), but fails again after the thread is resumed, because the extended path returns. Not a durable fix.
- Keeping threads closed and archiving immediately after a clean restart.
- Effectiveness: partial; cannot help the currently active thread, and any thread resumed afterwards regresses.
Expected behavior
Archiving should either normalize Windows extended-length paths before the move, or the thread store should stop persisting \\?\-prefixed paths in the first place. Previously archived threads with plain paths do not exhibit this failure, so normalizing at read/archive time should be sufficient.
Related issues
- [Windows] Cannot archive conversations when rollout paths use the \\?\ prefix #39150 - Cannot archive conversations when rollout paths use the
\\?\prefix - [Windows] Local thread archiving fails with thread-store os error 2 #39130 - Local thread archiving fails with thread-store os error 2
- Codex Desktop loses command/tool details after thread restore/archive, and archive restore path becomes inconsistent #26012 - Windows archive/restore path inconsistency
- Thread store resolves stale session_index entries to missing rollout files (state db returned stale rollout path) #31074 - Thread store resolves stale session_index entries to missing rollout files
- Fix Windows running thread resume path normalization #25509 - Related merged fix for Windows running-thread resume path normalization
- [Codex Desktop][Remote SSH] Archiving a thread fails with EXDEV when archived_sessions is on another filesystem #36531 - Archiving a thread fails when the archive move crosses filesystems
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
appIssues related to the Codex desktop appIssues related to the Codex desktop appbugSomething isn't workingSomething isn't workingsessionIssues involving session (thread) management, resuming, forking, naming, archivingIssues involving session (thread) management, resuming, forking, naming, archivingwindows-osIssues related to Codex on Windows systemsIssues related to Codex on Windows systems
Activity
github-actions commentedon Aug 18, 2026
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
RuriLothlorien commentedon Aug 18, 2026
This issue is intentionally kept as a complementary, consolidated report: it focuses on the empirical record of the attempted workarounds and why they are ineffective, rather than restating the original reproduction.
The key additional data points beyond #39150 / #39130 are:
\\?\prefix is actively re-persisted by the running app: stripping it fromstate_5.sqliteevery ~3 s does not stick; the app writes the extended form back within ~16 s for the active/resumed thread.renameworks for every combination of extended/plain path forms, which narrows the bug down to Codex's path handling rather than NTFS.Happy for maintainers to close this as a duplicate if preferred; the practical value is the workaround-effectiveness record above, which is also summarized in the #39150 thread.
RuriLothlorien commentedon Aug 18, 2026
Tested Codex Rescue on this machine as suggested (read-only commands only). Quick feedback:
codex-rescue@0.1.0-alpha.6(npm latest) fails to launch on Windows x64:platform package codex-rescue-win32-x64 is not installed, andcodex-rescue-win32-x64returns 404 on the npm registry.codex-rescue@0.1.0-alpha.6-2launches fine.doctor --all: 17 sessions scanned, 10 healthy, 7 with findings (mostlyINVALID_PERSISTED_ITEM_ID, plusINTERRUPTED_INPUT_NOT_DURABLE,UNFINISHED_TOOL_CALL,INCOMPLETE_ROLLOUT).doctor+workspaceon the two threads that currently fail to archive with the\\?\-prefixed rollout path:INVALID_PERSISTED_ITEM_ID; the other isHEALTHY.workspacereportsSaved Working Directory: unavailable (unknown)andWorkspace Association Health: UNRECORDEDfor both, so it does not currently surface the\\?\extended-path boundary on these affected legacy threads.Happy to share more (sanitized) output if useful.
Pdz1 commentedon Aug 19, 2026
Confirmed independently on Codex Desktop 26.814.41407.
Platform: Microsoft Windows NT 10.0.22631.0 x64.
I observed the same behavior:
I also encountered “thread not found” for an affected existing thread. No rollout JSONL files were missing.
N2meLess commentedon Aug 19, 2026
Still reproducible on Codex App 26.818.11542 on Windows. I independently observed the same
\\?\rollout path followed byos error 2when archiving. The referenced JSONL file still exists, and bothos.path.exists(path)andos.path.isfile(path)returnTrue.N2meLess commentedon Aug 19, 2026
Additional data point: I was able to archive one older thread successfully, then unarchive/resume it successfully. After that, its stored rollout_path was \?\C:..., and a second attempt to archive the same thread now fails with the same os error 2. I did not capture the DB path immediately before the first successful archive, so I can't prove the path rewrite is the sole trigger, but the failure appeared after the unarchive/resume cycle.
RuriLothlorien commentedon Aug 19, 2026
Consolidating the latest independent reports (thanks @Pdz1 and @N2meLess) into one picture for maintainers:
state_5.sqlite.threads.rollout_pathstored as\\?\C:\..., rollout JSONL present, archive fails with os error 2. Stripping the prefix allows an inactive thread to archive successfully; the active thread gets the prefix re-persisted almost immediately; the prefix also returns after an app restart.\\?\C:\...→ second archive fails" matches our local observation that resume re-persists the extended form. The failure appears right after a resume/unarchive cycle, i.e. when the thread store writes the rollout path back.Suggested fix directions:
rollout_path(especially on resume/unarchive), normalize Windows extended-length paths back to plainC:\...form, or\\?\inarchive_threadbefore the rename/comparison (e.g. inscoped_rollout_path/ path-scope checks), since previously archived threads with plain paths archive fine.This is no longer an isolated environment quirk: the same extended-path persistence and archive failure are reproducible across at least three machines/builds.
starkovalera commentedon Aug 19, 2026
Additional independent reproduction on Windows Codex Desktop:
This confirms the path form is actively produced by the current Desktop build and that the failure is in archive path handling. No chat contents, private paths, credentials, or source files are attached.
RuriLothlorien commentedon Aug 19, 2026
Thanks @shleder — the new
WINDOWS_ROLLOUT_PATH_IDENTITY_DIVERGENCEcheck is working as intended. Confirmed on this Windows machine withcodex-rescue@0.1.0-alpha.6-3:state_5.sqlite.threads.rollout_pathis currently stored in the\\?\C:\...form — 4/4 threads here, including two that reproduce the archiveos error 2and one newly created thread.doctor <rollout-file>runs surface the code directly; no raw paths, rollout content, or database files are needed for the finding.Two small observations for the tool:
doctor --alldid not list these threads or emit the code in my runs; only targeteddoctor <rollout-file>surfaced it. If the batch enumerates sessions differently (e.g., only catalog/index-discoverable ones), that may be worth a look.MALFORMED_RECORDalongside the divergence; it was actively being appended at scan time, so that reads as a live-writer tail rather than corruption.RuriLothlorien commentedon Aug 20, 2026
Quick consolidation of the latest independent confirmations (thanks @Culacco and @fireking0608-spec):
26.814.5517.0, bundled CLI0.148.0-alpha.15) across multiple Windows builds.\\?\C:\...form is re-persisted by the app after resume/use, and the archive failure returns.\\?\prefix while Codex is stopped makes the same backend archive/unarchive successfully.codex-cli 0.149.0-alpha.1) that contains the archive-path fix;0.148.0-alpha.15still fails on verbatim paths.Net: the Desktop package needs (a) archive-path normalization in its bundled thread-store, and (b) to stop re-persisting
\\?\C:\...rollout paths on resume.M-T-D-N commentedon Aug 21, 2026
Independent confirmation on Desktop 26.818.22352
I independently reproduced the same defect on another Windows x64 installation. This adds newer-build persistence and wider-state evidence:
thread/archiveattempts stopped after thread-listener teardown. Every affected row hadthreads.rollout_pathin the\\?\C:\...form.PRAGMA integrity_checkreturnedok. The wider audit found no database rows with missing rollout files, no archived-flag/location mismatches, no filename/thread-ID mismatches, and no duplicate canonical rollout paths.This supports the issue's existing conclusion: the source file is not missing, and inconsistent Windows path representation across persistence/list and archive stages is the likely proximate cause. The exact writer function and exact failing archive-stage operation remain inferred rather than source-traced.
A durable fix should normalize at the
threads.rollout_pathpersistence boundary and make archive path handling representation-independent. Regression coverage should include ordinary drive paths, verbatim drive paths, verbatim UNC paths, list/resume idempotence, and archive/unarchive round trips.No user paths, project names, thread/session IDs, raw logs, session contents, or database files are included.
AI disclosure
At the user's direction, this report transparently records that the user authorized the submission and completed the GitHub authentication step, while the investigation, analysis, drafting, and GitHub posting of this technical report were performed by an AI agent (OpenAI Codex) on the user's behalf.
RuriLothlorien commentedon Aug 21, 2026
Thanks @shleder — reran on
codex-rescue@0.1.0-alpha.7as requested (read-only). Results from this Windows machine:npx --yes codex-rescue@0.1.0-alpha.7now starts cleanly on Windows x64 (nocodex-rescue-win32-x64404).doctor <rollout-file>surfacesWINDOWS_ROLLOUT_PATH_IDENTITY_DIVERGENCEon every thread whosestate_5.sqlite.threads.rollout_pathis currently in the\\?\C:\...form (3/3 tested here, including a thread created today).doctor --allnow scans more sessions (25 vs ~20), butdoctor --all --jsonstill contains 0WINDOWS_ROLLOUT_PATH_IDENTITY_DIVERGENCE(3THREAD_IDENTITY_CONFLICTentries appear), and the currently-prefixed threads are still not listed by thread id in the batch output.So the recursive enumeration change helped coverage, but on this machine the divergence code still only appears via targeted
doctor <rollout-file>runs. Happy to provide more sanitized output if useful.RuriLothlorien commentedon Aug 22, 2026
Fixed-version confirmation (Windows):
26.818.5229.0; bundled/standalone CLI:codex-cli 0.149.0-alpha.4.1.state_5.sqlite.threads.rollout_pathwas still in the\\?\C:\...form (including a thread that previously failed with os error 2):thread/archivereturned success, the rollout moved toarchived_sessions, andarchived=1with a plain path.\\?\C:\...paths for new/active threads (14 such rows remain here), but archive now handles them correctly — i.e. archive-time path handling is representation-independent now, while the persistence-side normalization suggested earlier does not appear to be implemented yet.This matches the expected fix direction (handle the verbatim form at archive/read time) and resolves the practical failure on current builds.
RuriLothlorien commentedon Aug 24, 2026
Successfully archived threads
RuriLothlorien commentedon Aug 24, 2026
@shleder — I tested the newly published
@shleddy/vetto@next(0.2.0-alpha.2) on this Windows machine, read-only. Results:Batch discovery — fixed
vetto rescue scannow enumerates 59 sessions, including all 12 threads on this machine whosestate_5.sqlite.threads.rollout_pathis stored in the\\?\C:\...form. Previouslycodex-rescue doctor --all(alpha.7) skipped these and only targeteddoctor <file>surfaced them.sessions/YYYY/MM/DD/...) are included in the batch listing.Divergence diagnostic — not in this npm alpha yet
vetto rescue diagnose <key>on two affected verbatim-prefixed threads (including the currently active one) returnshealth: healthy,notices: [], and does not emitWINDOWS_ROLLOUT_PATH_IDENTITY_DIVERGENCE.mainand will land in a later npm alpha.Also noting the CLI rename:
doctoris nowrescue scan/rescue diagnose.Happy to rerun once a newer alpha with the inventory check ships. Thanks for moving this forward.