Desktop thread/resume can lock regular active threads after recent update
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 1419JSONL 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/codexmain
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/..., notarchived_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 1419lines- 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
22m52sand ended asturn_aborted. - Later Desktop reactivation attempts on
2026-06-18showthread/resumefromCodex Desktop26.611.62324. - Those resume attempts reach
resume_thread_with_history -> thread_spawn -> session_init -> shell_snapshot. Shell snapshot successfully createdis logged.- No follow-up
user_inputsubmission 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
1Mtokens:1585 - active threads over
10Mtokens:248 - active threads over
100Mtokens: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/resumeincludes reconstructed turn history inthread.turnsby default. excludeTurns: trueis documented as the cheap resume path that returns metadata/live resume state and lets clients page history viathread/turns/list.
codex-rs/app-server/src/request_processors/thread_processor.rs:
- Around
thread_processor.rs:2369-2389,ThreadResumeParamsincludesexclude_turns, andinclude_turns = !exclude_turns. - Around
thread_processor.rs:2493-2501, resume loads the response thread withinclude_turns. - Around
thread_processor.rs:2540-2564, the full-history path clones the thread for token usage replay, whileexcludeTurnsintentionally 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_remoteandcodex_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_inputor surface a clear error. - Forking should not be the only reliable way to continue work from a recently active thread.
Suggested investigation / fixes
- Have Desktop use
thread/resumewithexcludeTurns: trueby default, then page turn history withthread/turns/list. - Add telemetry around resume payload size, item count, turn count, token-usage replay time, reconstructed-turn count, and renderer time-to-interactive.
- Audit interrupted-turn restoration: a latest
turn_aborted/ interrupted turn should not leave the UI waiting forever or prevent newuser_inputfrom being submitted. - Audit metadata projection: DB
updated_at, rollout latest event, session metadata timestamp, andread_thread/Desktop summaryupdatedAtshould agree or have explicit semantics. - Add renderer-side virtualization/size caps for historical items, independent of app-server payload caps.
- Keep response-only redaction/compaction for huge historical tool/media payloads, but do not treat huge payloads as required for the bug.
Reproduction outline
- 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.
- Update to Codex Desktop
26.611.62324. - Reopen/continue the original active thread from Desktop.
- Observe app spin/lock. Logs show
thread/resumereaches shell snapshot success. - Try to send a message; no corresponding
user_inputsubmission appears for the affected thread. - Fork the thread and continue from the fork; this often works, indicating the underlying work can continue when the original resume state is bypassed.
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗