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.

Open 💬 7 comments Opened Apr 30, 2026 by defplus
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

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:

  1. On Windows, create a Codex App heartbeat automation attached to an existing local thread.
  2. Set the heartbeat interval to a short RRULE, for example:

FREQ=MINUTELY;INTERVAL=1

  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.
  2. Wait for the next heartbeat to fire against the same target thread.
  3. 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" />

View original on GitHub ↗

7 Comments

github-actions[bot] contributor · 2 months ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #20317
  • #19128
  • #19281

Powered by Codex Action

Deno2026 · 2 months ago

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:

  • OS: Windows
  • Codex Desktop package path: C:\Program Files\WindowsApps\OpenAI.Codex_26.506.3741.0_x64__2p2nqsd0c76g0\app\Codex.exe
  • Main state DB: C:\Users\aions\.codex\state_5.sqlite
  • App automation DB: C:\Users\aions\.codex\sqlite\codex-dev.db
  • Automation TOML directory: C:\Users\aions\.codex\automations\...

Primary failing thread / automation:

  • thread_id: 019e07b4-64e4-7c21-90d9-1c5f3301ee7c
  • automation: deno-registry-0-4-17-watch
  • automation kind: heartbeat

Observed error when manually running the automation:

cannot resume running thread 019e07b4-64e4-7c21-90d9-1c5f3301ee7c with stale path:
requested `C:\Users\aions\.codex\sessions\2026\05\08\rollout-2026-05-08T22-08-43-019e07b4-64e4-7c21-90d9-1c5f3301ee7c.jsonl`,
active `\\?\C:\Users\aions\.codex\sessions\2026\05\08\rollout-2026-05-08T22-08-43-019e07b4-64e4-7c21-90d9-1c5f3301ee7c.jsonl`

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:

  • When state_5.sqlite.threads.cwd and state_5.sqlite.threads.rollout_path are manually aligned to the active \\?\C:\... path spelling, heartbeat injection works again.
  • After repair, the heartbeat message successfully appears inside the same target session JSONL.

Confirmed working row after repair included:

cwd:          \\?\C:\Users\aions\Documents\Codex\2026-05-08\1-deno-comfyui-github-comfy-registry
rollout_path: \\?\C:\Users\aions\.codex\sessions\2026\05\08\rollout-2026-05-08T22-08-43-019e07b4-64e4-7c21-90d9-1c5f3301ee7c.jsonl

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:

  • The automation TOML can contain the expected thread-bound fields, including kind = "heartbeat", target_thread_id = "019e07b4-64e4-7c21-90d9-1c5f3301ee7c", and cwds = [...].
  • Meanwhile codex-dev.db.automations.cwds sometimes becomes [].
  • That 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:

  • A local guard script repairs drift every 5 minutes:

C:\Users\aions\.codex\automation_guard\codex_automation_guard.py

  • Scheduled Task: CodexHeartbeatAutomationGuard
  • The guard checks/repairs heartbeat TOML runtime fields and pins the thread path values in state_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:

  • The stale-path protection should remain, but it should compare canonicalized Windows paths or file identity, not raw path strings.
  • C:\...\rollout.jsonl and \\?\C:\...\rollout.jsonl should be treated as the same rollout file when they resolve to the same file.
  • Creating/updating/running automations should not desync state_5.sqlite.threads.rollout_path, runtime active thread path, and the automation resume request.
  • Since Codex allows only one active heartbeat automation per thread, creating another reminder/monitor in the same thread should update/merge into the existing heartbeat automation or clearly surface that behavior in the UI/agent flow.

This looks closely related to #20882 and the symlink/canonicalization class described in #21898 as well.

grantusmaximus · 2 months ago

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>.jsonl

The 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:

  • Heartbeat automations fail when manually run.
  • The session file exists and is readable via both path forms.
  • Restarting/recreating the heartbeat is only a workaround.

Expected:
Codex should canonicalize or otherwise compare Windows file identity before rejecting the resume as stale/mismatched.

shunichi-prog · 2 months ago

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:

  • Platform: Windows
  • Codex Desktop / session metadata CLI version: 0.131.0
  • Custom Codex home on a non-default drive: D:\Tools\Codex\Home
  • Action: selected an existing session from the left sidebar in order to view its log/history

Observed banner:

Failed to resume chat
cannot resume running thread <thread-id> with stale paths:
requested `\\?\D:\Tools\Codex\Home\sessions\2026\05\21\rollout-<thread-id>.jsonl`,
active `D:\Tools\Codex\Home\sessions\2026\05\21\rollout-<thread-id>.jsonl`

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 normal D:\... spelling.

Local state checks did not indicate session corruption:

  • The rollout JSONL exists and is readable.
  • The session is present in session_index.jsonl.
  • The thread row exists in state_5.sqlite.
  • In state_5.sqlite, threads.rollout_path was stored as the normal D:\... spelling while threads.cwd used the \\?\D:\... spelling.
  • logs_2.sqlite showed codex_app_server::request_processors::thread_lifecycle entries like composing running thread resume response for the same thread, with active_turn_present=false, active_turn_id=None, and active_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.

Giftia · 1 month ago

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 --check
  • brace structure check for the touched Rust files

Not run:

  • just fmt
  • cargo test -p codex-app-server

I could not open a PR directly because GitHub shows that openai/codex limits PR creation to collaborators.

Submitted with assistance from Codex agent.

Hiliboli · 1 month ago

I can confirm this is still reproducible on Windows with Codex Desktop heartbeat automations.

Environment:

  • Codex Desktop/App: 0.133.0-alpha.1 as shown in local logs
  • OS: Windows
  • Automation type: heartbeat
  • Pattern: two recurring heartbeat automations targeting existing local Codex threads, one every ~5 minutes and one every ~8-10 minutes

Observed behavior:

The automation intermittently fails to resume the target thread with the same stale/mismatched-path shape described here:

cannot resume running thread <redacted-thread-id> with stale path:
requested '<DRIVE>:\<codex-home>\.codex\sessions\YYYY\MM\DD\rollout-...-<redacted-thread-id>.jsonl',
active '\\?\<DRIVE>:\<codex-home>\.codex\sessions\YYYY\MM\DD\rollout-...-<redacted-thread-id>.jsonl'

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_path uses the \\?\... form, the heartbeat can resume again. However, after a successful heartbeat run, Codex Desktop sometimes writes the same threads.rollout_path value 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:

  1. Back up the local Codex state SQLite database.
  2. Update only the affected threads.rollout_path rows to the active \\?\... session path.
  3. Add local SQLite triggers that force those specific rows back to the \\?\... path if the app writes the ordinary path again.
  4. Add a local scheduled task as a belt-and-suspenders check that periodically verifies the same rows.

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:

  • Normalize/canonicalize equivalent Windows paths before comparing requested vs active session paths.
  • Treat C:\... and \\?\C:\... as the same file when they resolve to the same session JSONL.
  • More generally, the related symlink report in #21898 suggests this comparison should not be a raw string equality check.
  • If a heartbeat overlaps an active turn, it would be better to skip/delay that heartbeat with a clear "previous turn still active" state instead of failing the automation with a stale-path error for equivalent paths.

Privacy note: I redacted local drive layout, thread IDs, user names, and project-specific paths in this report.

sosiskin2000 · 1 month ago

I have another reproducible data point that narrows the trigger.

Environment:

  • Codex Desktop / app logs show app.version=0.133.0
  • Windows: Microsoft Windows NT 10.0.26200.0 x64
  • Automation type: heartbeat with target_thread_id
  • Schedule used for the test: RRULE:FREQ=MINUTELY;INTERVAL=6

Observed failure shape:

cannot resume running thread <thread-id> with stale path:
requested `C:\Users\<user>\.codex\sessions\...\rollout-<thread-id>.jsonl`,
active `\\?\C:\Users\<user>\.codex\sessions\...\rollout-<thread-id>.jsonl`

New trigger found: opening/clicking the heartbeat target thread in Codex Desktop.

Experiment:

  1. Normalized the relevant state_5.sqlite threads.rollout_path values from plain C:\... to \\?\C:\....
  2. Did not open the target thread in the Desktop UI.
  3. The heartbeat ran successfully 5 times:
  • 2026-05-27 Europe/Kiev: 17:09:02, 17:15:32, 17:22:02/03, 17:28:32, 17:35:02
  • Scheduled run failed automationId=duty-test: 0
  1. Then I clicked/opened the heartbeat target thread in Codex Desktop at about 17:47:55 Europe/Kiev.
  2. The next scheduled attempts failed immediately:
  • 17:48:01 stale path
  • 17:54:31 stale path

Additional observation:

  • After opening the target thread, the persisted threads.rollout_path values for the heartbeat target threads were again plain C:\....
  • The failure still reported the active running path as \\?\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 plain C:\.... 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.”