Codex cannot resume running thread when Windows session path differs only by \\?\ prefix
What happened?
After a Codex conversation has been running for a while, attempting to resume the existing running thread can fail with a stale path error. The two paths in the error appear to refer to the same session JSONL file, but one is a normal Windows path and the other uses the extended-length \\?\ path prefix.
Redacted example:
cannot resume running thread <THREAD_ID> with stale path: requested `C:\Users\<USER>\.codex\sessions\YYYY\MM\DD\rollout-YYYY-MM-DDTHH-MM-SS-<THREAD_ID>.jsonl`, active `\\?\C:\Users\<USER>\.codex\sessions\YYYY\MM\DD\rollout-YYYY-MM-DDTHH-MM-SS-<THREAD_ID>.jsonl`
These paths are equivalent on Windows, but Codex appears to treat them as different and refuses to resume the thread.
Expected behavior
Codex should resume the existing running thread when the requested and active session paths differ only by Windows path normalization, such as the presence or absence of the \\?\ extended-length prefix.
The user should not need to manually copy and paste the conversation into a new session to continue.
Actual behavior
Codex blocks resume with a stale path mismatch and requires starting a new session or manually transferring context.
Impact
This breaks continuity for long-running Codex sessions. The underlying session file still exists and appears to be the same file, but the resume logic rejects it because the path strings are formatted differently.
Likely cause
The resume logic may be comparing raw path strings rather than comparing normalized/canonical Windows filesystem paths.
Suggested fix
Normalize both paths before comparing them on Windows. For example:
- Treat
C:\...and\\?\C:\...as equivalent when they resolve to the same filesystem path. - Canonicalize both paths through the same Windows path API before comparison.
- Store internal session paths in one canonical format and only render user-facing paths separately.
Environment
OS: Windows
OS version observed: Microsoft Windows NT 10.0.26200.0
Shell observed: PowerShell 7.6.1
Codex session storage path: C:\Users\<USER>\.codex\sessions\...
Repository: openai/codex
Redaction note
The original username, thread ID, timestamp, and exact session file name were redacted in this report.
7 Comments
Root cause located: the resume guard compares rollout paths with raw
PathBufequality instead of the normalization helper the rest of the codebase already uses.The stale-path check is in
resume_running_thread,codex-rs/app-server/src/request_processors/thread_processor.rs(around L2786–L2799 on56958f2):The two operands come from different sources and can legitimately differ in their Windows normalization form:
requested_path=params.path, passed straight from the client (plainC:\Users\...\rollout-….jsonl).active_path= the running thread's recordedrollout_path()(the extended-length\\?\C:\Users\...form, exactly as shown in the report).PathBuf'sPartialEqis a bytewise comparison of the underlying OS string, so\\?\C:\…andC:\…are unequal even though they resolve to the same file → resume is rejected with the stale-path error.This guard is the only path comparison in this area that doesn't normalize first. The repo already ships the right primitive —
codex_utils_path::paths_match_after_normalization(codex-rs/utils/path-utils/src/lib.rs), which canonicalizes both operands (on Windowsstd::fs::canonicalizemaps bothC:\…and\\?\C:\…to the same extended-length form) and falls back to raw equality if canonicalization fails. It's used for resume/cwd matching intui/src/session_resume.rs,tui/src/resume_picker.rs,rollout/src/recorder.rs,exec/src/lib.rs, and even in this same file at L3516 for the thread-listcwdfilter — just not in this resume guard.There's already a
#[cfg(windows)]unit test covering exactly this case (utils/path-utils/src/path_utils_tests.rs,matches_windows_verbatim_paths): it assertspaths_match_after_normalization(\\?\<dir>, <dir>)istrue.Suggested fix (outline): replace the raw
requested_path != active_pathwith!path_utils::paths_match_after_normalization(requested_path, active_path).path_utilsis already imported and used in this file, so no new dependency. Equivalent paths (verbatim\\?\prefix, and also the case-insensitive/mnt/<drive>WSL form handled by the same helper) would then resume correctly, while genuinely different paths still hit the guard via the raw-equality fallback. A regression test inapp-server/tests/suite/v2/thread_resume.rsmirroring the existing stale-path test, but with a verbatim-vs-plain pair, would lock this in (on Windows).Happy to put up a PR with this change + test if a maintainer wants to take it
I’m seeing the same issue in Codex Desktop on Windows with a heartbeat automation attached to an existing thread.
Observed error:
Context:
destination=threadcan temporarily rebind it, but the same stale path error can recur.\\?\prefix and appear to refer to the same session JSONL file.Impact: recurring heartbeat automations become unreliable because they fail to resume the current running thread, even though the target thread/session file is the same.
Expected: the resume/stale-path check should canonicalize Windows paths or compare file identity so
C:\...and\\?\C:\...are treated as equivalent when they resolve to the same file.Here's my Codex generated comment when I encountered this error...
I hit this exact issue on Windows today, and the error signature matched this report exactly: the requested path was a normal
C:\...path and the active path was the same file in\\?\C:\...form.A few details from my case in case they help confirm scope:
019e7898-cccf-7b41-8215-f39dbae306c9The concrete error was:
cannot resume running thread 019e7898-cccf-7b41-8215-f39dbae306c9 with stale path: requested 'C:\Users\Shark\.codex\sessions\2026\05\30\rollout-2026-05-30T12-15-40-019e7898-cccf-7b41-8215-f39dbae306c9.jsonl', active '\\?\C:\Users\Shark\.codex\sessions\2026\05\30\rollout-2026-05-30T12-15-40-019e7898-cccf-7b41-8215-f39dbae306c9.jsonl'Workaround that worked for me: fully quit Codex and reopen it. After restart, I was able to resume the chat normally.
So from the user side, a full app restart seems to clear the stale running-thread state, but the underlying bug still looks exactly like the raw path comparison described above.
FYI. It is still doing this. Even with the newest update from 5 minutes ago.
I am seeing the same stale-path resume failure on a Windows host, with one extra detail: it is triggered through remote access and restarting Codex only fixes it temporarily.
Environment:
0.136.0-alpha.2OpenAI.Codex_26.601.2237.0_x64__2p2nqsd0c76g0Observed:
Impact:
This looks consistent with a raw string comparison of rollout paths before Windows path normalization/canonicalization.
Additional reproduction evidence from Windows Codex Desktop 26.601.2237.0.
I hit the same stale-path class again on thread
019e8d38-69a3-76a0-96e1-ceea6b8d1be9:Local evidence:
state_5.sqlitestill contains the thread row.rollout_pathis stored as normalC:\...cwdis stored as extended path\\?\C:\...session_index.jsonlcontains the same thread id twice with different thread names.read_threadin the app reports the thread asidle, so it is not obviously a real actively-running thread from the user's point of view.A few concrete observations that may help narrow the bug:
session_index.jsonlentries for the same thread id may be correlated with the bad resume state.Observed app/process environment:
OpenAI.Codex_26.601.2237.0_x64__2p2nqsd0c76g0codex.exe app-server --listen stdio://processes were present when the issue was observed.What would help most:
cwd,rollout_path, and in-memory active-thread bindings.Follow-up from the same Windows host: this has recurred after a restart workaround.
Timeline:
Current process state still shows the Windows Codex desktop process and
codex.exe app-serverrunning, so this appears to be the remote/thread-state path issue recurring while the host-side processes remain alive, rather than a simple app-server process crash.