Codex Desktop: thread/read fails on empty rollout after closing browser sidebars

Open 💬 2 comments Opened Jun 1, 2026 by zhanex

What issue are you seeing?

Codex Desktop on Windows showed a JavaScript/UI error after all browser/sidebar panes were closed. The desktop logs show the browser sidebar window being removed, and a later app-server/UI path shows thread/read failing because a precomputed rollout file existed but was still empty. After that failure, Electron continued receiving events for a conversation that the UI had not loaded, producing repeated unknown conversation errors.

Observed environment:

  • Codex Windows Store package: OpenAI.Codex_26.527.3686.0_x64__2p2nqsd0c76g0
  • App log release field: 26.527.31326
  • OS: Windows 10.0.26200
  • Locale/timezone: zh-CN, Asia/Shanghai

Relevant sanitized log excerpts:

2026-06-01T06:48:43.849Z info [browser-sidebar-manager] IAB_LIFECYCLE syncing browser use active state conversationId=<redacted> isActive=false ownerWebContentsId=1 turnId=null windowId=1
2026-06-01T06:48:43.850Z info [browser-sidebar-manager] IAB_LIFECYCLE syncing browser use active state conversationId=<redacted> isActive=false ownerWebContentsId=1 turnId=null windowId=1
2026-06-01T06:48:43.923Z info [browser-session-registry] IAB_LIFECYCLE closed browser sidebar page conversationId=<redacted> windowId=1
2026-06-01T06:48:43.927Z info [browser-session-registry] IAB_LIFECYCLE closed browser sidebar page conversationId=<redacted> windowId=1
2026-06-01T06:48:43.927Z info [browser-session-registry] IAB_LIFECYCLE removed browser session window windowId=1
2026-06-01T13:12:00.856Z info [electron-message-handler] IAB_LIFECYCLE webview captured browser use session route conversationId=<redacted> disposeAfterSessionActivity=true reason=hydrated_collab_thread
2026-06-01T13:12:00.927Z info [AppServerConnection] response_routed broadcastFallback=false conversationId=<redacted> durationMs=69 errorCode=-32603 hadInternalHandler=false hadPending=true method=thread/read originWebcontentsId=1 targetDestroyed=false
2026-06-01T13:12:00.929Z error [electron-message-handler] Request failed conversationId=<redacted> durationMs=72 error={"code":-32603,"message":"failed to read thread: thread-store internal error: failed to read thread C:\\Users\\<user>\\.codex\\sessions\\2026\\06\\01\\rollout-2026-06-01T21-12-00-<redacted>.jsonl: rollout at C:\\Users\\<user>\\.codex\\sessions\\2026\\06\\01\\rollout-2026-06-01T21-12-00-<redacted>.jsonl is empty"} method=thread/read
2026-06-01T13:12:06.209Z error [electron-message-handler] Received turn/started for unknown conversation conversationId=<redacted>
2026-06-01T13:12:09.095Z error [electron-message-handler] Received item/started for unknown conversation conversationId=<redacted>
2026-06-01T13:12:16.243Z error [electron-message-handler] Conversation state not found conversationId=<redacted>

What steps can reproduce the bug?

The desktop UI trigger is timing-sensitive, but this was observed after closing all browser/sidebar panes so the final browser session window is removed.

The app-server path is reproducible with:

  1. Start a new thread so the response includes a precomputed rollout path.
  2. Ensure the rollout path exists as a zero-byte file before the first user message materializes the rollout.
  3. Call thread/read with includeTurns: false while the thread is already loaded in memory.

Current behavior treats the empty rollout file as a hard -32603 internal error instead of falling back to the live loaded thread snapshot.

What is the expected behavior?

Closing the final browser/sidebar pane should not leave the desktop UI in an error state. For a loaded thread whose precomputed rollout path exists but is still empty, thread/read should treat that rollout as not yet materialized and return the live thread snapshot for metadata-only reads.

For includeTurns: true, the server should continue returning the existing user-facing "not materialized yet" invalid-request response before the first user message.

Additional information

I found no exact duplicate issue for empty rollout, thread/read, and unknown conversation. I prepared a small patch with a regression test and a fix in ThreadRequestProcessor that only treats empty rollout errors as "missing" when the corresponding thread is already loaded in memory; see the issue comment for the fork branch because GitHub rejected opening a PR from my account.

View original on GitHub ↗

2 Comments

zhanex · 2 months ago

Update: I prepared a minimal patch branch, but GitHub rejected creating a PR against openai/codex from my fork:

GraphQL: zhanex does not have the correct permissions to execute `CreatePullRequest` (createPullRequest)

The branch and commit are available here for maintainers:

The patch adds a regression test and updates ThreadRequestProcessor so a loaded thread can service metadata-only thread/read from the live snapshot when the precomputed rollout path exists but is still empty.

ken-jo · 1 month ago

I hit the same failure mode on a newer Windows Codex Desktop build, with a slightly different user-facing trigger: intermittent Desktop/phone connection trouble recovered after restarting the phone-side Codex app.

Environment:

  • Windows Codex Desktop package: OpenAI.Codex_26.623.9142.0_x64
  • Desktop log release field: 26.623.70822
  • Platform: win32
  • Local timezone: KST
  • Incident candidate: 2026-07-01 12:08:35 KST (2026-07-01T03:08:35Z)

Sanitized evidence:

2026-07-01T03:08:34.977Z info [browser-session-registry] browser_use_iab_backend_startup_ready backend=iab platform=win32 release=26.623.70822 sessionId=<redacted>
2026-07-01T03:08:35.573Z info [AppServerConnection] response_routed ... errorCode=-32603 ... method=thread/read ...
2026-07-01T03:08:35.573Z error [electron-message-handler] Request failed ... method=thread/read ... error={"code":-32603,"message":"failed to read thread: thread-store internal error: failed to read thread <redacted-user-path>\\rollout-2026-07-01T12-08-34-<redacted>.jsonl: rollout at <redacted-user-path>\\rollout-2026-07-01T12-08-34-<redacted>.jsonl is empty"}

The same rollout file was not permanently empty:

  • Created: 2026-07-01 12:08:35 KST
  • Last write: 2026-07-01 12:11:11 KST
  • Final size: 296113 bytes
  • Final line count: 92

Follow-on pattern for the same conversationId in this log:

  • unknown conversation: 257
  • No turns for conversation: 150
  • Conversation state not found: 13
  • rollout at .* is empty: 1

This supports the race-condition interpretation in the issue: thread/read observes a newly-created rollout path before the first record is materialized, returns a fatal internal error, and the renderer/app-server path then fails to associate subsequent events with the conversation even though the rollout later becomes readable.