Desktop thread/resume can lock regular active threads after recent update

Open 💬 4 comments Opened Jun 18, 2026 by 100yenadmin

Summary

Codex Desktop 26.611.62324 can lock up / spin indefinitely when reactivating regular active threads that worked before the latest Desktop update. Forking the affected thread and continuing from the fork can work around it, which makes this look like a resume/reactivation regression rather than an underlying model/tool failure.

The first local investigation over-emphasized one thread with a large inline historical image payload. A second affected thread shows the same user-visible failure shape while being small on disk:

  • active, non-archived thread
  • rollout file about 2.2 MB
  • 1419 JSONL records
  • max JSONL line about 98 KB
  • no giant base64 image line

So this should not be treated only as "large files/images break resume." The stronger hypothesis is a regression in Desktop's thread/resume handling, full-history turn reconstruction/rendering, token-usage replay, interrupted-turn restoration, or thread metadata projection.

Environment

  • Codex Desktop: 26.611.62324
  • Bundle version: 4028
  • macOS app bundle modified locally: 2026-06-17 22:08 +0700
  • App-server process: /Applications/Codex.app/Contents/Resources/codex app-server --analytics-default-enabled
  • Source checkout inspected: openai/codex main

Affected regular active thread examples

Example A: small active thread that worked before update

Thread id: 019ed1ea-d71a-7bc0-92d5-06d85ce9ba74

Local store row:

  • archived = 0
  • rollout path under ~/.codex/sessions/..., not archived_sessions
  • created at 2026-06-17 02:31:29 +0700
  • file modified / last rollout event at 2026-06-18 01:14:39 +0700
  • tokens_used = 29,445,232
  • rollout size about 2.2 MB
  • 1419 lines
  • max line about 98 KB
  • latest event is turn_aborted

Timeline:

  • The thread was created and completed useful work before the local app update time.
  • The app bundle was modified at 2026-06-17 22:08 +0700.
  • A later turn after the update ran for about 22m52s and ended as turn_aborted.
  • Later Desktop reactivation attempts on 2026-06-18 show thread/resume from Codex Desktop 26.611.62324.
  • Those resume attempts reach resume_thread_with_history -> thread_spawn -> session_init -> shell_snapshot.
  • Shell snapshot successfully created is logged.
  • No follow-up user_input submission is logged for that thread after the resume attempt, even when the user is trying to message/continue it.
  • The Desktop UI spins/locks; forking the thread and continuing from the fork is the practical workaround.

There is also a metadata/projection oddity for this thread: a Codex-native read-thread summary reported top-level updatedAt equal to the creation timestamp, while SQLite and the rollout file both show later activity through the aborted turn. That suggests the UI/protocol may be mixing session metadata, DB metadata, and reconstructed turn state inconsistently.

Example B: active thread with larger historical payloads

Thread id: 019ec65f-8b05-74a1-9461-76e71dca37ad

This one is also active / non-archived and shows the same resume-to-shell-snapshot-then-spin shape. Its rollout is only about 4.6 MB, but it contains a function_call_output with an inline data:image/png;base64,... input_image line of about 680 KB, plus several large historical tool-output metadata records. That makes it a useful stress case, but Example A above shows the regression is not limited to giant image payloads.

Broader local signals

Recent local state has many active threads with very large tokens_used values despite modest on-disk rollout sizes:

  • active threads: 2929
  • active threads over 1M tokens: 1585
  • active threads over 10M tokens: 248
  • active threads over 100M tokens: 176

This may be normal cumulative accounting for long-running sessions, but it matters because thread/resume can replay restored token usage and rebuild turns. If the Desktop client is eager-rendering the whole history and/or waiting on token usage replay/state reconstruction, relatively small files can still become pathological.

Relevant source pointers

codex-rs/app-server/README.md:

  • Around README.md:277-279, thread/resume includes reconstructed turn history in thread.turns by default.
  • excludeTurns: true is documented as the cheap resume path that returns metadata/live resume state and lets clients page history via thread/turns/list.

codex-rs/app-server/src/request_processors/thread_processor.rs:

  • Around thread_processor.rs:2369-2389, ThreadResumeParams includes exclude_turns, and include_turns = !exclude_turns.
  • Around thread_processor.rs:2493-2501, resume loads the response thread with include_turns.
  • Around thread_processor.rs:2540-2564, the full-history path clones the thread for token usage replay, while excludeTurns intentionally skips that expensive replay path.

codex-rs/app-server/src/request_processors/thread_lifecycle.rs:

  • populate_thread_turns_from_history(...) reconstructs turns from rollout history for the response path.

codex-rs/app-server/src/request_processors/thread_resume_redaction.rs:

  • Current resume redaction is scoped to mobile remote clients only (codex_chatgpt_android_remote and codex_chatgpt_ios_remote).
  • It does not address Desktop's default full-history resume path.

Expected behavior

Reactivating a regular active thread should not lock the Desktop app.

At minimum:

  • A malformed, interrupted, or state-heavy historical thread should fail fast with a per-thread error.
  • Desktop should remain responsive.
  • Sending a new message after resume should either submit a user_input or surface a clear error.
  • Forking should not be the only reliable way to continue work from a recently active thread.

Suggested investigation / fixes

  1. Have Desktop use thread/resume with excludeTurns: true by default, then page turn history with thread/turns/list.
  2. Add telemetry around resume payload size, item count, turn count, token-usage replay time, reconstructed-turn count, and renderer time-to-interactive.
  3. Audit interrupted-turn restoration: a latest turn_aborted / interrupted turn should not leave the UI waiting forever or prevent new user_input from being submitted.
  4. Audit metadata projection: DB updated_at, rollout latest event, session metadata timestamp, and read_thread/Desktop summary updatedAt should agree or have explicit semantics.
  5. Add renderer-side virtualization/size caps for historical items, independent of app-server payload caps.
  6. Keep response-only redaction/compaction for huge historical tool/media payloads, but do not treat huge payloads as required for the bug.

Reproduction outline

  1. Use a stored active thread created before the latest update with a few completed turns, a compaction, nontrivial token usage, and a later interrupted/aborted turn.
  2. Update to Codex Desktop 26.611.62324.
  3. Reopen/continue the original active thread from Desktop.
  4. Observe app spin/lock. Logs show thread/resume reaches shell snapshot success.
  5. Try to send a message; no corresponding user_input submission appears for the affected thread.
  6. Fork the thread and continue from the fork; this often works, indicating the underlying work can continue when the original resume state is bypassed.

View original on GitHub ↗

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