Repository navigation
Desktop thread/resume can lock regular active threads after recent update #28867
Description
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.
Activity
github-actions commentedon Jun 18, 2026
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
100yenadmin commentedon Jun 18, 2026
Correction / additional evidence after a second affected thread was inspected:
The original title/body over-narrowed this to large historical payloads. A second regular active thread shows the same failure shape while being small on disk: about 2.2 MB, 1419 JSONL records, max line about 98 KB, active/non-archived, with no giant inline base64 image line.
The stronger signal is a recent Desktop resume/reactivation regression:
thread/resume -> resume_thread_with_history -> session_init -> shell_snapshotShell snapshot successfully createdis loggeduser_inputsubmission appears for that thread when the user tries to continue/message itI updated the issue title/body to reflect that large payloads are only one stress case, not a required condition. Suspect areas are full-history resume, token usage replay, interrupted-turn restoration, metadata projection, and/or eager Desktop rendering of reconstructed history.
[-]Desktop thread/resume can lock renderer on large historical turn payloads[/-][+]Desktop thread/resume can lock regular active threads after recent update[/+]100yenadmin commentedon Jun 18, 2026
Implementation update with patch branches and corrected framing:
This still looks like a recent Desktop resume/reactivation regression, not only an oversized or image-heavy history bug. Redacted local evidence from 2026-06-18 includes regular active sessions under
~/.codex/sessions, including019ec65f-8b05-74a1-9461-76e71dca37adand a later forked continuation019ed1ea-d71a-7bc0-92d5-06d85ce9ba74. One affected active session was small enough to rule out “only giant session” as the root cause: about 2.2 MB, 1419 JSONL records, max line about 98 KB, and no giant inline base64 image line. Another affected thread had only two image references. The observed log shape remains:thread/resumereaches session init / shell snapshot,Shell snapshot successfully createdappears, and no later user input submission is observed for that original thread while Desktop spins/locks. Forking the thread works around the stuck original.I published three upstream patch branches from current
main(commit2c7802e7cf) on a fork. GitHub currently blocks this account from opening PRs againstopenai/codexwithGraphQL: 100yenadmin does not have the correct permissions to execute CreatePullRequest, so these are compare links rather than PR links:thread/readbug: https://github.com/openai/codex/compare/main...100yenadmin:codex/thread-read-updated-at?expand=1The metadata branch is a concrete fix for #28870. The lightweight-resume branch makes the public TUI use
excludeTurns + initialTurnsPageand exposes those resume fields in generated schemas so clients do not have to eagerly consume full history. The diagnostics branch is intentionally non-mutating: it logs only counts/classes/estimated sizes for resume payloads plus token-usage replay duration, with no raw message text or session contents.I still would not claim a single 95%-proven root cause for the active Desktop lockup. The current best split is: #28870 is patchable metadata freshness, this issue tracks the active resume lockup, #26352/#28316 track image-heavy/full-history stress, and #28868 stays separate for archive/cold-storage robustness.
100yenadmin commentedon Jun 18, 2026
@tibo-openai
hossy-0322 commentedon Aug 11, 2026
I can reproduce what appears to be the same underlying Desktop resume/history-loading issue on Windows, and I collected some additional measurements that may help separate the base resume cost from the large-history amplification.
Environment:
OpenAI.Codex 26.803.10989.00.147.0-alpha.6.6codex-cli 0.147.0The key finding is that this is not only a very-large-rollout problem. On first open of an existing thread,
thread/readis fast (4-9 ms), butthread/resumeconsistently takes several seconds even for modest persisted histories:thread/resumeThe Large case had 1,535 tool calls, 919 tool outputs, and 17 compactions. After its 6.612 s
thread/resume, Desktop issued 21thread/turns/listrequests. Their serial response sequence continued for about 16.45 s, with the last response about 28.60 s after the initial thread-view event.This aligns with the concern here that the problem is not reducible to a single large image or file. The additional measurements also complement the Windows symptom report in #29590: they separate a base resume cost on small/medium threads from a second serial turns-list hydration cost on large, tool-heavy threads.
During earlier controlled first-open/switch samples, the bundled backend temporarily reached about 1.2 GiB private memory and high multi-core CPU (up to about 1109% aggregate CPU in one switch sample, roughly 11 logical cores rather than 1109% of a single core). Electron main and the active renderer also spiked. GPU utilization remained low (at most about 6%), and idle Desktop/backend CPU was low. The standalone CLI is responsive on the same machine.
WPR CPU plus File I/O showed the bundled backend accessing the selected rollout during resume, but physical disk throughput was not the limiting factor: the 123 MiB rollout had only an 8 KiB physical read in the trace, consistent with filesystem cache. Electron main primarily read Chromium caches and app resources, with no evidence that it bulk-read the rollout.
This suggests two related product paths worth measuring separately:
thread/resume/ materialization cost that affects small and medium threads; andthread/turns/listhydration cost for large, tool-heavy histories.I can provide additional sanitized aggregate measurements if useful; raw ETL, rollout JSONL, logs, prompts, and local paths are intentionally not attached.