Codex Desktop: new chats fail to resume while rollout JSONL is briefly empty
What version of the Codex App are you using (From “About Codex” dialog)?
26.810.41047 (build 6570)
What subscription do you have?
20x Max
What platform is your computer?
Darwin 25.4.0 arm64 arm
What issue are you seeing?
Every newly started chat can immediately show this error:
Failed to resume chat
failed to read thread: thread-store internal error: failed to read session metadata
<redacted>/rollout-<redacted>.jsonl: rollout at <redacted>/rollout-<redacted>.jsonl is empty
The rollout later becomes non-empty, so this does not appear to be permanent session corruption.
Local diagnostic timing shows:
thread/startsucceeds.turn/startfollows.- The app calls
thread/resumeroughly 37 ms afterthread/start. - The rollout path already exists, but is still zero bytes while the background writer gathers Git/session metadata.
- The running-thread resume path tries to read persisted session metadata and treats the transient empty file as a fatal error.
This appears to be a startup race in the app-server running-thread resume path.
What steps can reproduce the bug?
- Open Codex Desktop on macOS.
- Start a new chat in an existing Git repository.
- Submit a prompt.
- Observe the red “Failed to resume chat” error immediately after startup.
- Inspect the referenced rollout path at the time of the error: the file exists at zero bytes, then becomes a valid non-empty JSONL shortly afterward.
The app-server behavior can be reproduced more directly:
- Start a thread and retain its live thread ID and rollout path.
- Start the first turn.
- Allow the rollout path to exist as a zero-byte file before the first metadata record is persisted.
- Call
thread/resumefor that running thread. - Observe that resume fails while reading session metadata from the empty rollout.
What is the expected behavior?
A newly started chat should open without an error toast.
When the requested thread is still running in memory and its live rollout file exists but is temporarily empty, thread/resume should recover by persisting the current thread snapshot and retrying the metadata read (or otherwise wait/retry until metadata is available).
Threads that are genuinely unmaterialized and have no rollout file should keep the existing “not materialized yet” behavior.
Additional information
Related reports cover adjacent paths, but not this exact failure:
- #25621 covers
thread/readencountering an empty rollout after a different UI trigger. - #38451 covers a Worktree startup
thread/resumerace where no rollout is found. - This report covers
thread/resumefor a running new chat when the rollout exists but is still empty.
A focused patch and regression test are already prepared:
- Branch: https://github.com/alpheay/codex/tree/nik/recover-empty-running-rollout
- Commit: https://github.com/alpheay/codex/commit/8e95422508
- Compare: https://github.com/openai/codex/compare/main...alpheay:codex:nik/recover-empty-running-rollout
The patch only repairs a zero-byte rollout for a thread that is already running in memory. It preserves the current error behavior for threads with no materialized rollout.
Verification completed:
just fmtjust fix -p codex-app-serverjust test -p codex-app-server thread_resume_repairs_empty_running_rolloutjust test -p codex-app-server thread_resume_rejects_unmaterialized_threadjust test -p codex-app-server thread_resume_with_empty_path_uses_running_thread_id
If this approach aligns with the intended app-server behavior, I would be happy to submit the prepared change if invited.
3 Comments
Confirmed on a newer build after updating today:
26.810.50856(build6644)0.148.0-alpha.926.6.1(25G76), arm64A fresh local chat reproduced the same race. Sanitized timeline (UTC):
The failed resume therefore occurred 74 ms before the first persisted metadata record. The referenced rollout subsequently grew to 897,247 bytes / 153 valid JSONL records, parsed cleanly, and the task continued running.
A read-only scan of local desktop logs for Aug 1-15 found 222 distinct rollout paths that logged the same transient empty-rollout failure. Every one of those files is now non-empty and begins with
session_meta. That supports this being a recurring startup/hydration race rather than persistent transcript corruption.No raw transcript, full log, session ID, username, or project content is attached because those may contain private data.
This transient zero-byte rollout race is a useful false-positive/control case for
codex-rescue. I’m field-testing whether diagnostics distinguish “temporarily not materialized yet” from durable corruption instead of treating every empty-file observation as a broken session.If you can reproduce it in a disposable Codex home, please run after the thread has stabilized:
A healthy result after the first
session_metaappears is the expected useful outcome. If Rescue still classifies the session as damaged, that would be a bug in its diagnosis. No salvage is needed for this test.Please share only sanitized output, versions and exit codes—no raw rollout/log DB, prompts, credentials, thread IDs, or private paths. Repo: https://github.com/shleder/codex-rescue
Corroborating this exact failure on macOS with a newer desktop build.
Environment:
26.810.52044(CFBundleVersion6662)codex-cli 0.148.0-alpha.9Sanitized timing from the desktop log for a brand-new local thread:
The resume attempt therefore occurred about 32 ms before the rollout's first metadata record. The same rollout subsequently became a valid 481,872-byte JSONL and the task continued running; there were no zero-byte rollout files left afterward.
The user-visible result was the red
Failed to resume chatbanner immediately after starting a new thread. This independently confirms thatthread_hydration/thread/resumecan race initial rollout materialization for a newly created thread, rather than indicating stale-session recovery or permanent transcript corruption.