Codex App automation/heartbeat repeatedly fails to resume a running thread on Windows because the same session JSONL path is compared with and without the extended path prefix.
What version of the Codex App are you using (From “About Codex” dialog)?
26.429.20946
What subscription do you have?
Pro x20
What platform is your computer?
Microsoft Windows NT 10.0.26200.0 x64
What issue are you seeing?
Codex App automation/heartbeat repeatedly fails to resume a running thread on Windows because the same session JSONL path is compared with and without the extended path prefix.
Error:
cannot resume running thread 019ddff0-80cb-7f42-8317-8daf17d0bd7f with mismatched path:
requested 'C:\Home\.codex\sessions\2026\05\01\rollout-2026-05-01T04-49-34-019ddff0-80cb-7f42-8317-8daf17d0bd7f.jsonl',
active '\\?\C:\Home\.codex\sessions\2026\05\01\rollout-2026-05-01T04-49-34-019ddff0-80cb-7f42-8317-8daf17d0bd7f.jsonl'
Expected:
These paths should be canonicalized as the same file before comparing active vs requested session path.
Impact:
Codex App automations/heartbeats stop frequently. This has happened dozens of times over the last 3 days.
Environment:
Windows
Codex Desktop
CLI version seen in session logs: 0.126.0-alpha.8
Automation type: heartbeat
What steps can reproduce the bug?
This is intermittent, but I have been able to trigger it repeatedly with Codex App heartbeat automations on Windows, especially when the heartbeat interval is short (for example 1 minute) and the previous heartbeat run is still active or has only just finished.
Steps to reproduce:
- On Windows, create a Codex App heartbeat automation attached to an existing local thread.
- Set the heartbeat interval to a short RRULE, for example:
FREQ=MINUTELY;INTERVAL=1
- Let the heartbeat perform a task that can take longer than the interval, or close/reopen/resume the app while the heartbeat thread is active.
- Wait for the next heartbeat to fire against the same target thread.
- The automation sometimes fails to resume the thread with a path mismatch, even though both paths refer to the same JSONL session file.
Observed error:
cannot resume running thread 019ddff0-80cb-7f42-8317-8daf17d0bd7f with mismatched path:
requested 'C:\Home\.codex\sessions\2026\05\01\rollout-2026-05-01T04-49-34-019ddff0-80cb-7f42-8317-8daf17d0bd7f.jsonl',
active '\\?\C:\Home\.codex\sessions\2026\05\01\rollout-2026-05-01T04-49-34-019ddff0-80cb-7f42-8317-8daf17d0bd7f.jsonl'
Expected behavior:
Codex should canonicalize Windows paths before comparing the requested session path with the active session path. In this case, C:\Home\... and \\?\C:\Home\... are the same file, so the resume should not fail only because one path has the extended-length prefix.
Actual behavior:
The heartbeat automation stops/fails because the active running thread path and requested path are treated as different. This has happened dozens of times over the last ~3 days.
Session id from the example above:
019ddff0-80cb-7f42-8317-8daf17d0bd7f
Notes:
This seems more likely when the heartbeat interval is shorter than the duration of the previous run. Increasing the interval from 1-6 minutes to 20-30 minutes reduces the frequency, but does not address the underlying path normalization issue.
I do not have a minimal standalone code snippet, but the core comparison issue is equivalent to treating these two Windows paths as unequal:
requested = "C:\\Home\\.codex\\sessions\\2026\\05\\01\\rollout-2026-05-01T04-49-34-019ddff0-80cb-7f42-8317-8daf17d0bd7f.jsonl"
active = "\\\\?\\C:\\Home\\.codex\\sessions\\2026\\05\\01\\rollout-2026-05-01T04-49-34-019ddff0-80cb-7f42-8317-8daf17d0bd7f.jsonl"
These should be normalized/canonicalized before comparison.
What is the expected behavior?
Expected behavior:
Codex App should treat Windows paths that refer to the same session JSONL file as equivalent before comparing the requested session path with the active running thread path.
In particular, these two paths should be canonicalized to the same file:
C:\Home\.codex\sessions\2026\05\01\rollout-2026-05-01T04-49-34-019ddff0-80cb-7f42-8317-8daf17d0bd7f.jsonl
\\?\C:\Home\.codex\sessions\2026\05\01\rollout-2026-05-01T04-49-34-019ddff0-80cb-7f42-8317-8daf17d0bd7f.jsonl
A heartbeat automation should not fail to resume a thread solely because one path includes the Windows extended-length prefix (\\?\) and the other does not.
If the target thread is still actively running, Codex should either wait, skip the overlapping heartbeat gracefully, or report that the previous run is still active. It should not permanently stop or fail the automation with a mismatched-path error for equivalent paths.
Additional information
I attached a screenshot of the error message.
The key detail in the screenshot is that the requested path and active path point to the same session JSONL file, but one uses the normal Windows path form and the other uses the extended-length path prefix:
requested:
C:\Home\.codex\sessions\2026\05\01\rollout-2026-05-01T04-49-34-019ddff0-80cb-7f42-8317-8daf17d0bd7f.jsonl
active:
\\?\C:\Home\.codex\sessions\2026\05\01\rollout-2026-05-01T04-49-34-019ddff0-80cb-7f42-8317-8daf17d0bd7f.jsonl
This has happened repeatedly over the last few days with heartbeat automations.
<img width="729" height="152" alt="Image" src="https://github.com/user-attachments/assets/a2c51c97-4c54-4c09-b099-7ffecc700717" />
7 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Adding another confirmed Windows reproduction that appears to be the same underlying bug, still present in the Codex Desktop app/CLI context
0.130.0-alpha.5.Environment:
C:\Program Files\WindowsApps\OpenAI.Codex_26.506.3741.0_x64__2p2nqsd0c76g0\app\Codex.exeC:\Users\aions\.codex\state_5.sqliteC:\Users\aions\.codex\sqlite\codex-dev.dbC:\Users\aions\.codex\automations\...Primary failing thread / automation:
thread_id:019e07b4-64e4-7c21-90d9-1c5f3301ee7cdeno-registry-0-4-17-watchheartbeatObserved error when manually running the automation:
The two paths point to the same rollout JSONL; the only difference is normal DOS path spelling vs Windows extended-length path spelling.
Manual repair temporarily fixes it:
state_5.sqlite.threads.cwdandstate_5.sqlite.threads.rollout_pathare manually aligned to the active\\?\C:\...path spelling, heartbeat injection works again.Confirmed working row after repair included:
However, the failure can recur after later automation create/update/run activity, which suggests some part of the app/server/automation path is writing or requesting the normal
C:\...spelling again while the active thread runtime is holding the extended\\?\C:\...spelling.Additional observation:
kind = "heartbeat",target_thread_id = "019e07b4-64e4-7c21-90d9-1c5f3301ee7c", andcwds = [...].codex-dev.db.automations.cwdssometimes becomes[].cwds = []drift does not appear to be the primary failure, because heartbeat can still work after the thread path row is repaired. The critical failure seems to be the stale-path guard comparing equivalent Windows paths by spelling rather than canonical path/file identity.Current local workaround:
C:\Users\aions\.codex\automation_guard\codex_automation_guard.pyCodexHeartbeatAutomationGuardstate_5.sqlite.This workaround is only defensive. It repairs the state after drift occurs, but the root issue appears to be in the resume-path comparison / path canonicalization layer.
Expected fix:
C:\...\rollout.jsonland\\?\C:\...\rollout.jsonlshould be treated as the same rollout file when they resolve to the same file.state_5.sqlite.threads.rollout_path, runtime active thread path, and the automation resume request.This looks closely related to #20882 and the symlink/canonicalization class described in #21898 as well.
I am seeing the same issue on Windows Codex Desktop with heartbeat automations.
Manual "Run now" fails with:
cannot resume running thread <redacted-thread-id> with stale path:
requested
C:\Users\<user>\.codex\sessions\<date>\rollout-<redacted>.jsonl,active
\\?\C:\Users\<user>\.codex\sessions\<date>\rollout-<redacted>.jsonlThe requested and active paths refer to the same JSONL file; one path uses the normal Windows form and the other uses the extended-length
\\?\prefix.Impact:
Expected:
Codex should canonicalize or otherwise compare Windows file identity before rejecting the resume as stale/mismatched.
Adding another Windows Codex Desktop reproduction that appears to be the same underlying path-normalization bug, but this one was triggered by a manual sidebar resume, not by an automation/heartbeat.
Scenario:
0.131.0D:\Tools\Codex\HomeObserved banner:
The requested and active paths point to the same rollout JSONL. The only difference is the Windows extended-length path prefix. In this reproduction the direction is the reverse of some earlier examples: the requested path has the
\\?\prefix, while the active path is the normalD:\...spelling.Local state checks did not indicate session corruption:
session_index.jsonl.state_5.sqlite.state_5.sqlite,threads.rollout_pathwas stored as the normalD:\...spelling whilethreads.cwdused the\\?\D:\...spelling.logs_2.sqliteshowedcodex_app_server::request_processors::thread_lifecycleentries likecomposing running thread resume responsefor the same thread, withactive_turn_present=false,active_turn_id=None, andactive_turn_status=None.So this looks like the app/server still considered the thread "running" even though no active turn was present, then rejected the sidebar resume because the stale-path guard compared two equivalent Windows paths by spelling rather than canonical file identity.
This suggests the issue affects manual session resume from the Codex Desktop UI as well as heartbeat/automation resume. The stale-path protection should remain, but it likely needs to normalize/canonicalize Windows paths, or compare file identity, before deciding that the requested and active rollout paths are different.
I have a candidate fix available here:
https://github.com/Giftia/codex/tree/codex/fix-resume-rollout-path-equivalence
Commit:
https://github.com/Giftia/codex/commit/929c4b2f57f22b058c846f9f6ad690c9774e75d2
This changes the running-thread resume stale-path check to compare rollout paths by canonicalized file identity before rejecting the request. It preserves the stale-path rejection when paths are genuinely different or cannot be canonicalized.
It should address the Windows
C:\...vs\\?\C:\...mismatch reported in this issue, and also covers symlink-equivalent rollout paths.Testing done:
git diff --checkNot run:
just fmtcargo test -p codex-app-serverI could not open a PR directly because GitHub shows that
openai/codexlimits PR creation to collaborators.Submitted with assistance from Codex agent.
I can confirm this is still reproducible on Windows with Codex Desktop heartbeat automations.
Environment:
0.133.0-alpha.1as shown in local logsObserved behavior:
The automation intermittently fails to resume the target thread with the same stale/mismatched-path shape described here:
The two paths point to the same JSONL file. I verified this locally by checking that both the normal Windows path and the
\\?\extended path exist and have the same file length.A notable detail: after manually fixing the stored thread row so
threads.rollout_pathuses the\\?\...form, the heartbeat can resume again. However, after a successful heartbeat run, Codex Desktop sometimes writes the samethreads.rollout_pathvalue back to the ordinary<DRIVE>:\...form. The next heartbeat then fails again because the active in-memory path is still the extended\\?\...form.Temporary local workaround I used:
threads.rollout_pathrows to the active\\?\...session path.\\?\...path if the app writes the ordinary path again.This is only a workaround and not a recommended product fix. It is fragile because it mutates local app state outside the app.
Suggested product-side fix:
C:\...and\\?\C:\...as the same file when they resolve to the same session JSONL.Privacy note: I redacted local drive layout, thread IDs, user names, and project-specific paths in this report.
I have another reproducible data point that narrows the trigger.
Environment:
app.version=0.133.0Microsoft Windows NT 10.0.26200.0 x64target_thread_idRRULE:FREQ=MINUTELY;INTERVAL=6Observed failure shape:
New trigger found: opening/clicking the heartbeat target thread in Codex Desktop.
Experiment:
state_5.sqlitethreads.rollout_pathvalues from plainC:\...to\\?\C:\....17:09:02,17:15:32,17:22:02/03,17:28:32,17:35:02Scheduled run failed automationId=duty-test: 017:47:55Europe/Kiev.17:48:01stale path17:54:31stale pathAdditional observation:
threads.rollout_pathvalues for the heartbeat target threads were again plainC:\....\\?\C:\....Interpretation:
Opening/resuming the heartbeat target thread in the Desktop UI appears to put the active thread into an extended-path form (
\\?\C:\...) while the scheduler/persisted requested path is plainC:\.... The next heartbeat then fails the stale-path check even though both paths refer to the same rollout JSONL file.This seems like the same root cause as this issue, but with a narrower and repeatable UI trigger: “open the heartbeat target thread, then wait for the next scheduled heartbeat.”