openai / openai/codex

Windows: `thread/archive` fails with "os error 2" after `thread/resume` stores a `\\?\` (verbatim) rollout_path — same file queued twice

Open
#39,239 26 comments 5 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

app app-server bug session windows-os
Dominant language
Rust
Stars
125k
Forks
19.4k
PR merge metrics
PR metrics pending

Description

Summary

On Windows, once a thread has been resumed, archiving it fails with:

failed to archive session: thread-store internal error: failed to archive thread: The system cannot find the file specified. (os error 2)

The rollout file exists and is readable. Root cause is a path-equality mismatch in archive_thread_with_paths that causes the same rollout file to be renamed twice.

Environment

  • Codex desktop 26.814.5167.0 (release 26.814.41407), bundled CLI 0.148.0-alpha.15
  • Windows 11 (build 26200)

Repro

  1. Open (resume) any existing thread in the desktop app.
  2. threads.rollout_path in state_5.sqlite is now stored as \\?\C:\Users\<user>\.codex\sessions\...\rollout-...jsonl (verbatim prefix — looks like std::fs::canonicalize output). Threads that have not been opened keep the plain C:\Users\<user>\.codex\sessions\...\rollout-...jsonl form.
  3. Archive that thread → error above. The file is still in sessions/ afterward.
  4. Workaround that confirms the diagnosis: strip the \\?\ prefix from that row's rollout_path, then archive without re-opening → succeeds. Re-opening the thread re-introduces the prefix and the failure.

Analysis (codex-rs/thread-store/src/local/archive_thread.rs)

In archive_thread_with_paths:

  • rollout_paths comes from owned_rollout_paths_from_index(&reference_index, ...) — a filesystem scan → plain C:\... paths.
  • selected_rollout_path comes from thread_rollout_resolver::resolve_current → the SQLite row → \\?\C:\....
  • if !rollout_paths.contains(&selected_rollout_path) { rollout_paths.push(selected_rollout_path) } compares PathBufs byte-wise, so the verbatim and non-verbatim forms of the same file are treated as different and both are queued.
  • Each is then passed through scoped_rollout_path (helpers.rs), which canonicalizes both to the identical source and computes the identical destination.
  • First std::fs::rename succeeds; the second fails with NotFound because the source was just moved. restore_rollout_moves then rolls the first move back — hence the file "still exists" and the misleading error.

Suggested fix (either/both)

  • Dedup rollout_moves after canonicalization (compare canonical source paths, or dedup by rollout id/filename) rather than contains on mixed-form paths beforehand.
  • Don't persist verbatim (\\?\) paths on resume; store the same form the scanner produces (e.g. dunce::canonicalize, or strip the verbatim prefix on Windows).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in codex-rs/thread-store/src/local/archive_thread.rs at archive_thread_with_paths, then read scoped_rollout_path in helpers.rs and the thread_rollout_resolver path handling. Reproduce the Windows resume-then-archive flow and verify that the same rollout is queued only once and archiving completes without restoring a failed move.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust, sqlite
Domain
cli, operating-systems
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
74/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.