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 ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗