Codex Desktop: new chats fail to resume while rollout JSONL is briefly empty
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.5k
- PR merge metrics
- PR metrics pending
Description
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.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in the codex-app-server thread/resume handling described by the issue, then run the named regression tests: thread_resume_repairs_empty_running_rollout, thread_resume_rejects_unmaterialized_thread, and thread_resume_with_empty_path_uses_running_thread_id. Done means a running thread with a temporarily empty rollout resumes without an error, while an unmaterialized thread keeps its existing behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100