Codex Desktop macOS: unarchive updates local state, then returns `failed to read unarchived thread`; thread appears after restart

Open 💬 1 comment Opened Jul 17, 2026 by oorangee97

Summary

On the macOS desktop app, Settings → Archived chats → Unarchive intermittently shows a red failure toast and returns JSON-RPC error -32603:

failed to unarchive session: thread-store internal error:
failed to read unarchived thread <codex_home>/sessions/YYYY/MM/DD/rollout-<redacted-thread-id>.jsonl

However, the storage mutation has often already succeeded:

  • the rollout has moved from archived_sessions/ to sessions/YYYY/MM/DD/;
  • state_5.sqlite.threads.archived is already 0;
  • rollout_path already points to the active sessions path;
  • after fully quitting and reopening the app, the thread appears in the left sidebar and works normally.

This is therefore a false-negative unarchive result plus a stale Desktop UI, rather than data loss.

Environment

  • Desktop app display name: ChatGPT
  • Bundle identifier: com.openai.codex
  • Desktop version: 26.715.21425
  • Bundle build: 5488
  • Bundled CLI: codex-cli 0.145.0-alpha.18
  • Platform: macOS 26.5.2, Darwin 25.5.0 arm64
  • Observed: 2026-07-17

Frequency and local evidence

In one day of desktop logs:

  • 4 failed thread/unarchive calls across 3 distinct local threads;
  • 3 successful thread/unarchive calls in the same period;
  • one affected thread produced the same failure twice;
  • failed calls returned in roughly 18–52 ms, with no preceding network timeout.

Sanitized sequence:

T+0ms   Unarchive requested conversationId=<redacted>
T+18ms  method=thread/unarchive errorCode=-32603
T+51ms  Request failed:
        failed to unarchive session: thread-store internal error:
        failed to read unarchived thread <codex_home>/sessions/.../<redacted>.jsonl

Post-failure checks:

state_5.sqlite integrity_check: ok
affected rollout JSONL parse checks: all passed
thread row: archived=0
rollout_path: <codex_home>/sessions/YYYY/MM/DD/<redacted>.jsonl
restart Desktop: thread appears in sidebar

No raw logs, thread IDs, task titles, prompts, account data, or real local paths are included here.

Size correlation

The three failed unarchive attempts involved rollout files of approximately:

  • 18.8 MB
  • 24.4 MB
  • 31.5 MB

Three successful attempts in the same period involved rollout files of approximately:

  • 2.5 MB
  • 2.8 MB
  • 4.0 MB

All six were ordinary readable JSONL files. This suggests that long/large histories may make the final summary-read path more likely to fail, but this evidence does not establish a fixed byte threshold.

Suspected cause

The current unarchive implementation appears to:

  1. rename the rollout into sessions/YYYY/MM/DD/;
  2. mark the state DB row unarchived;
  3. call read_thread_item_from_rollout(...);
  4. return an internal error if that final read yields None.

Source:
https://github.com/openai/codex/blob/08e30a2e4e38187f38f59aa4778c9213b56ff00e/codex-rs/thread-store/src/local/unarchive_thread.rs#L56-L89

There is no rollback after steps 1–2. Therefore a failure at step 3 can return an error even though the unarchive mutation is already committed. The Desktop UI then remains stale until restart.

It would also help if the error preserved the underlying reason why read_thread_item_from_rollout returned no item, rather than collapsing it to the generic failed to read unarchived thread message.

Steps to reproduce

The failure is intermittent and appears more common with long local threads:

  1. Create/use a sufficiently long local Desktop thread.
  2. Archive it.
  3. Open Settings → Archived chats.
  4. Click Unarchive.
  5. Observe a red failure toast containing failed to read unarchived thread.
  6. Fully quit and reopen the desktop app.
  7. Observe that the thread is now present in the active left sidebar.

Expected behavior

  • A successfully moved and DB-updated thread should produce a successful unarchive response.
  • The active and archived lists should refresh immediately.
  • If summary hydration fails after the mutation, the app should either:
  • return success and refresh using persisted DB metadata; or
  • roll back the mutation atomically and report the underlying parse/read reason.
  • Repeated clicks should not be required.

Actual behavior

  • The API reports unarchive failure.
  • The UI shows a red failure toast and does not immediately show the thread.
  • The underlying thread is often already unarchived.
  • Restarting the app makes it appear in the left sidebar.

Related issues, but not exact duplicates

  • #11907 reports that restored conversations may not refresh until restart, but does not include the -32603 failed to read unarchived thread false-negative after the local mutation already succeeded.
  • #20317 concerns a persistent sessions/archived_sessions path mismatch that restart does not fix.
  • #27202 concerns missing hostId and archived-list discoverability.

This report adds the exact app-server error, storage/DB post-state, restart behavior, same-day success/failure comparison, and rollout-size correlation.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗