Codex Desktop: new chats fail to resume while rollout JSONL is briefly empty

Open 💬 3 comments Opened Aug 14, 2026 by alpheay

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/start succeeds.
  • turn/start follows.
  • The app calls thread/resume roughly 37 ms after thread/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?

  1. Open Codex Desktop on macOS.
  2. Start a new chat in an existing Git repository.
  3. Submit a prompt.
  4. Observe the red “Failed to resume chat” error immediately after startup.
  5. 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:

  1. Start a thread and retain its live thread ID and rollout path.
  2. Start the first turn.
  3. Allow the rollout path to exist as a zero-byte file before the first metadata record is persisted.
  4. Call thread/resume for that running thread.
  5. 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/read encountering an empty rollout after a different UI trigger.
  • #38451 covers a Worktree startup thread/resume race where no rollout is found.
  • This report covers thread/resume for a running new chat when the rollout exists but is still empty.

A focused patch and regression test are already prepared:

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 fmt
  • just fix -p codex-app-server
  • just test -p codex-app-server thread_resume_repairs_empty_running_rollout
  • just test -p codex-app-server thread_resume_rejects_unmaterialized_thread
  • just 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.

View original on GitHub ↗

3 Comments

lookslikelove · 13 days ago

Confirmed on a newer build after updating today:

  • ChatGPT/Codex Desktop: 26.810.50856 (build 6644)
  • Bundled Codex CLI: 0.148.0-alpha.9
  • macOS 26.6.1 (25G76), arm64

A fresh local chat reproduced the same race. Sanitized timeline (UTC):

11:02:49.677  Conversation created
11:02:49.893  thread/read succeeded
11:02:49.898  turn/start succeeded
11:02:49.911  thread/resume failed with -32603: rollout is empty
11:02:49.985  first session_meta record was written

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.

shleder · 11 days ago

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:

pipx install codex-rescue
codex-rescue sessions
codex-rescue doctor --latest

A healthy result after the first session_meta appears 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

cypherkitty · 11 days ago

Corroborating this exact failure on macOS with a newer desktop build.

Environment:

  • ChatGPT/Codex desktop build: 26.810.52044 (CFBundleVersion 6662)
  • Bundled Codex: codex-cli 0.148.0-alpha.9
  • Platform: macOS on Apple Silicon

Sanitized timing from the desktop log for a brand-new local thread:

19:54:42.044 thread/start succeeded
19:54:42.092 maybe_resume_started
19:54:42.129 Conversation created
19:54:42.386 turn/start succeeded
19:54:42.446 thread/resume failed: rollout ... is empty
19:54:42.478 first session_meta record timestamp

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 chat banner immediately after starting a new thread. This independently confirms that thread_hydration/thread/resume can race initial rollout materialization for a newly created thread, rather than indicating stale-session recovery or permanent transcript corruption.