[Windows Desktop 26.715] Completed large thread is fully replayed every few seconds, causing system-wide input stutter

Open 💬 13 comments Opened Jul 17, 2026 by PrinnyQ
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What version of Codex is running?

  • Codex Desktop package: 26.715.2305.0
  • Desktop client version in app-server traces: 26.715.21425
  • Bundled WSL Codex runtime: 0.145.0-alpha.18

What operating system are you using?

Windows 10 Pro x64, version 10.0.19045 (24 logical processors, 128 GB RAM), with the Codex app-server running through WSL2.

What is the issue?

A large thread that has already emitted task_complete and is no longer active continues to be polled by Codex Desktop with thread/turns/list.

Each request reconstructs the entire rollout (about 167 MB / 94,706 items). This repeats indefinitely while the Desktop app is open and causes:

  • delayed typing in the composer;
  • mouse-pointer and general Windows UI stutter every 1–2 seconds;
  • lag even while viewing a different project/thread;
  • occasional loss of responsiveness around session navigation.

Task switching is not required. The stutter continues while the app is simply left open.

Sanitized trace pattern:

app_server.client_name="Codex Desktop"
app_server.client_version="26.715.21425"
rpc.method="thread/turns/list"
Resuming rollout from "<redacted>.jsonl"
Resumed rollout with 94706 items

The latest turn had already ended with task_complete, but the same Desktop connection continued issuing these requests.

Steps to reproduce

  1. Have a large local thread (in this case about 167 MB and 94.7k reconstructed items).
  2. Let its current turn finish and emit task_complete.
  3. Switch to another thread/project, or leave Codex Desktop idle.
  4. Keep Codex Desktop open and move the mouse or type in Codex/another Windows app.
  5. Observe periodic whole-system input/UI stutter.
  6. Fully quit Codex Desktop: the stutter stops immediately.
  7. Use Codex CLI with Desktop closed: the system remains smooth.
  8. Reopen Desktop: the periodic stutter returns.

Measurements

Over one five-minute sample after the thread had completed:

  • 34 complete whole-rollout replays;
  • mean gap between replay completions: about 7.16 seconds;
  • cache-warmed replay duration: about 3.65–4.52 seconds each;
  • app-server sustained about 1.02 CPU cores, with about 1.87 cores observed during an earlier replay/startup sample;
  • app-server RSS: about 409 MB;
  • the settled Windows frontend used only about 0.06 CPU core in a comparison sample.

This is not memory exhaustion; the machine has 128 GB RAM.

The rollout was also copied, with matching hash, from the Windows-mounted filesystem to WSL ext4:

  • before: each full replay took about 33.7–45.5 seconds and was largely I/O-bound;
  • after: the initial resume took 6.87 seconds and later replays took 3.65–4.52 seconds;
  • however, the polling/replay loop continued, became CPU-bound, and the system-wide stutter remained.

The state database passed quick_check, the JSONL is valid, and there were no repeated rollout parse errors. Moving storage therefore improves each scan but does not fix the repeated full-history hydration.

Expected behavior

  • A completed, inactive thread should not be continuously polled.
  • thread/turns/list should use indexed/cached metadata and true pagination instead of reconstructing the complete JSONL for every request.
  • Background status/session refresh should not hydrate an entire transcript.
  • Desktop should not affect mouse or system-wide input responsiveness while idle.
  • Any unavoidable history indexing should be coalesced, cancellable, and run at low priority.

A/B isolation

  • Codex Desktop open: periodic system-wide stutter.
  • Codex Desktop fully closed: stutter disappears immediately.
  • Codex CLI alone: smooth.
  • Faster WSL-local storage: individual scans are faster, but the loop and stutter remain.

Related issues

  • #33382 — system-wide stutter during task switching; this report does not require switching and identifies repeated full-rollout hydration.
  • #22411 — app-server loads session files on thread/list.
  • #32198 — full replay during thread/turns/list; that report includes legacy parse errors, while this rollout has no parse errors.
  • #25215 — large-rollout resume/list limits.
  • #33774 — separate history/project-mapping regression observed around the same Desktop upgrade.

I have intentionally omitted the rollout, databases, thread IDs, titles, local paths, prompts, and raw trace files because they contain private project data. I can provide additional sanitized counters or a synthetic large-rollout reproducer if maintainers specify the preferred format.

View original on GitHub ↗

13 Comments

github-actions[bot] contributor · 1 month ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #33774
  • #33016
  • #33285

Powered by Codex Action

fengjikui · 1 month ago

Adding a macOS arm64 reproduction because this now appears cross-platform and app-server-side rather than specific to WSL I/O.

Environment:

  • macOS 15.7.4, arm64
  • Codex Desktop client 26.715.31925
  • bundled app-server / CLI 0.145.0-alpha.18

In a sanitized 75-second sample, Desktop issued 22 thread/turns/list requests. The app-server completed 20 full reconstructions of the same 615,541,816-byte legacy rollout, producing 281,148 items each time. During the loop it was at about 101.6% CPU and 13.16 GiB RSS. Earlier in the same launch, a separate 4,246,305,774-byte legacy rollout was reconstructed 16 times (99,084 items per reconstruction, about 10-11 seconds each). The state-store backfill is already complete and these replays have no rollout parse errors.

Current main documents the expensive branch directly: paginated histories use the ThreadStore path, while legacy thread/turns/list calls load_thread_turns_list_history; the comment says it "still replays the entire rollout on every request" until turn metadata is indexed separately:

The reader streams every line, parses it into serde_json::Value, clones/deserializes it into RolloutLine, and retains all items in a Vec. This explains why repeated polling becomes both CPU- and memory-heavy at multi-GB scale. Transparent storage compression helps disk usage but does not remove the full decode/parse/rebuild on each request.

Possible landing order: stop or deduplicate unnecessary client polling first; add app-server single-flight/caching keyed by stable rollout identity as an immediate guard; then migrate/index legacy turn metadata so pagination no longer reconstructs the full file. I have omitted thread IDs, titles, local paths, and content.

zaptrem · 1 month ago

Same defect on macOS 26.5.2 (arm64), with a symbolized native profile pinning the hot path. I filed #34915 before finding this issue; closing that as a duplicate and consolidating the evidence here.

Environment: Codex Desktop 26.715.72359 (build 5718), Codex Framework 150.0.7871.124, macOS 26.5.2 (25F84), Mac17,8.

  • Two still-active sessions with rollouts of 679 MB and 582 MB. Unlike the completed-thread case in the OP, these are live threads — so the replay loop runs at steady state whenever the app is open, and the full ingest restarts after every app relaunch.
  • The app-server holds ~210–228% CPU and ~2.6–2.8 GB RSS from the first minute after relaunch and does not settle (20 s samples over ~3 min; ~6 min of CPU time consumed in the first 2m46s of process lifetime).
  • sample <pid> 3 on the busy app-server — hot frames:
codex_app_server::request_processors::thread_processor::build_thread_turns_page_response
codex_app_server::request_processors::build_legacy_api_turns_from_rollout_items
codex_app_server_protocol::protocol::thread_history::ThreadHistoryBuilder::handle_rollout_item
codex_app_server_protocol::protocol::thread_history::ThreadHistoryBuilder::handle_event
codex_protocol::dynamic_tools::normalize_dynamic_tool_specs
codex_protocol::items::parse_hook_prompt_message

i.e. the time is in thread/turns/list page construction re-parsing rollout items from the raw JSONL, matching the replay counts measured in this thread. lsof shows both rollouts held open (two fds each) continuously. An earlier profile on the previous app build additionally showed heavy serde_json deserialization under tokio fs reads.

  • Possibly-related fallout on the same machine: recurring V8 OOM aborts in the git worker thread (the #34213 signature) every ~8–16 h since 07-18; each crash-relaunch cycle repeats the full rollout re-ingest.
grtninja · 1 month ago

A concrete client-side reference implementation may help with the pagination/cache boundary here.

In a separate local companion client, bounded detail polls were replacing prior UI history, so we implemented a monotonic bounded merge instead of rehydrating the complete transcript on every refresh:

  • treat the newest detail response as a bounded window/delta, not the whole authority;
  • union it with the client’s retained bounded scrollback;
  • give runtime events a stable identity (call_id, otherwise timestamp + role/kind/event_type/tool name);
  • replace a stale runtime card in place when the same identity arrives again;
  • preserve ordinary messages chronologically;
  • deduplicate once and apply one explicit retention cap after merging.

That implementation is merged in grtninja/PennyGPT-Lite#9 (mergeCodexThreadMessages) and was validated with regression tests for both older-scrollback preservation and exactly-once runtime-card replacement; current-head CI also covered typecheck, tests, and build.

This is not an upstream patch or proof of the same internal code path. It is evidence that Desktop/app-server can avoid full-history replay while preserving a coherent UI if the protocol exposes a stable cursor/delta and event identities. A likely product split is:

  1. server: indexed pagination/cursor and no rollout reconstruction for completed inactive threads;
  2. client: bounded monotonic union keyed by stable event IDs, with stale runtime cards replaced rather than appended;
  3. lifecycle: stop background polling entirely after task_complete unless an explicit subscription/version changes.

That would address both the repeated 167 MB hydration and the common temptation to fix missing history by requesting the entire transcript every few seconds.

heithmurray · 1 month ago

I can now reproduce this exact failure on the current unified Codex/ChatGPT Desktop build, with direct local measurements.

Environment

  • Windows 10 x64, build 19045
  • Installed package: OpenAI.Codex_26.721.4979.0
  • Desktop client version recorded by app-server: 26.721.41059
  • Large task rollout: approximately 708 MB
  • Reconstructed item count: approximately 132,583
  • Rollout parses successfully with zero corruption and zero parse errors

Reproduction and trace

While working in a different task, Codex Desktop continued polling the large May task in the background. After reopening the large task, the same behavior continued:

  • thread/turns/list issued by Codex Desktop every roughly 7–8 seconds
  • each request logs Resuming rollout and reconstructs all ~132.5k items
  • 61 related log rows / 40 distinct timestamps were recorded in one five-minute window
  • measured codex.exe read rate averaged about 86 MB/s and peaked around 108 MB/s during a 15-second sample
  • an earlier 10-second sample recorded approximately 892 MB read by codex.exe

This is not failed compaction or a corrupt rollout. The large task worked before the recent Desktop update. The current client appears to ignore the practical compaction boundary and repeatedly reconstruct the complete physical JSONL.

We also found and eliminated two plausible local-state triggers:

  1. A stale restored localhost browser pane was surgically removed from both global-state files.
  2. A stranded queued follow-up (Run ended before the steer was accepted) later disappeared from both state files.

Neither changed the seven-second thread/turns/list replay. The loop therefore appears to be Desktop client behavior rather than a recoverable local-state entry.

User impact

The impact is severe and not confined to the Codex window:

  • CPU remains heavily loaded while Desktop is open.
  • Mouse movement, keyboard input, clipboard operations, and dictation become delayed or unreliable.
  • Windows UI responsiveness degrades.
  • The app has produced repeated Application Hang events.
  • Fully closing Desktop stops the replay and restores normal responsiveness.
  • CLI use without Desktop does not produce the same behavior.

I lost approximately three working days diagnosing and containing this regression. I also downgraded from the $200 Pro plan because I cannot justify paying that amount for a desktop client that currently prevents productive work.

Storage clarification

The repeated history scan creates substantial read amplification. Persistent SQLite TRACE/WAL churn is also present, but current physical-disk measurements did not show the extreme sustained write rates reported in the worst SSD-endurance cases. I am not claiming the SSD is already damaged. The confirmed defect is the continuous full-history replay, resulting CPU load, SQLite/logging churn, and system-wide input degradation.

Requested fix

Please prioritize:

  • stopping background polling of completed or inactive tasks;
  • true indexed/paginated thread/turns/list behavior that does not reconstruct the complete JSONL;
  • caching/coalescing task status refreshes;
  • a supported way to disable or recover a pathological Desktop task without deleting its history;
  • bounded persistent logging and WAL maintenance;
  • a regression test using a large, compacted task on Windows.

Private paths, task contents, thread IDs, raw logs, and account details have been omitted. I can provide additional sanitized counters if maintainers specify the preferred format.

heithmurray · 1 month ago

One additional note: I am available and willing to work directly with OpenAI/Codex maintainers on this reproduction. Please tag or reply to me here if you need specific sanitized traces, counters, A/B checks, or confirmation against a candidate build.

I want the product fixed and am happy to help with a focused maintainer-led investigation. What I cannot continue doing is spending additional working days independently reverse-engineering and containing a Desktop release regression just to regain basic usability.

heithmurray · 1 month ago

A further product-impact detail should be recorded: the troubleshooting experience inside Codex compounded the regression.

The user repeatedly identified that the failure began with the Desktop update and that previously healthy large tasks were being handled differently. The assistant nevertheless spent too long exploring weaker local explanations involving GPU labels, antivirus behavior, Windows configuration, hardware, and persisted UI state. The user had to restate the same core evidence many times before the investigation traced the live thread/turns/list replay.

The assistant also treated a stranded queued follow-up as a likely root cause and prepared a surgical state repair before verifying that removing the entry stopped the replay. The entry later disappeared, while the seven-to-eight-second full-history reconstruction continued unchanged. That disproved the proposed cause.

This matters because the regression did not only make Desktop unusable. It also made the built-in assistant less effective at diagnosing the product failure, forcing the user to act as the investigator, repeatedly challenge premature conclusions, and spend substantially more time reaching the actual app-server trace.

A better diagnostic path would have been immediate inspection of live app-server requests, measurement of repeated rollout reconstruction, and comparison against current upstream reports before proposing local repairs. The combination of the Desktop defect and the assistant-led troubleshooting detours materially increased the user’s time loss and reduced trust in the product.

mingisrookie · 1 month ago

Corroborating data point from another Windows machine (native, no WSL).

Environment

  • Codex Desktop 26.721.4979.0, app-server codex-cli 0.146.0-alpha.3.1 (native Windows)
  • Windows 11, 24 GB RAM
  • ~/.codex/sessions: 718 rollout .jsonl files, 1.4 GB total, largest single file 39 MB

Observation

After ~8 hours of uptime, the app-server process (codex.exe app-server) had accumulated:

ReadTransferCount:  30.4 GB   (sessions dir is only 1.4 GB → ~22x read amplification)
WriteTransferCount:  5.2 GB
CPU time:            1382 s
Working set:         427 MB

Measured via Get-CimInstance Win32_Process. The 30 GB cumulative read against a 1.4 GB corpus is consistent with rollouts being fully re-read/replayed repeatedly rather than incrementally indexed. Symptoms match: UI increasingly sluggish over the day, recovered after killing the app-server.

Archiving old rollouts out of ~/.codex/sessions (718 → 473 files) noticeably reduced the load after restart, which also points at full-corpus rescans.

rdylina · 26 days ago

Related current-status update from macOS: the thread-history/session rehydration problem appears to have accelerated with recent Codex Desktop updates. On the current build (26.727.51351), the renderer now crashes/reloads every 2–3 minutes during active use, making the application nearly unusable. The main app process remains alive while the window blanks and reloads, with Crashpad reporting renderer failures. This may be a more severe manifestation of the repeated history rehydration described here.

meza · 26 days ago

Related native-Windows data point from current Desktop client 26.727.51351 and app-server 0.146.0-alpha.9.2:

Opening an active task with an approximately 12 MiB, 4.9k-item rollout produced nine thread/turns/list requests within roughly two seconds. Every request reconstructed the complete rollout. Eleven complete reconstructions occurred across the observed task-opening sequence.

I have not established the continuous idle polling reported in this issue. This narrower observation shows that the same expensive complete-history path can also amplify a single navigation operation at a substantially smaller history size.

Full reproduction: https://github.com/openai/codex/issues/25390#issuecomment-5152708349.

louis030195 · 22 days ago

Adding a current macOS profile with a high thread count and direct packaged-client inspection. No thread IDs, titles, prompts, paths, or rollout contents are included.

Environment

  • ChatGPT/Codex Desktop 26.727.51351 (build 6119)
  • bundled codex-cli 0.146.0-alpha.9.2
  • macOS 26.6, Apple Silicon

Privacy-safe profile and process evidence

  • 84,988 indexed threads: 83,131 active and 1,857 archived
  • every indexed thread is history_mode=legacy; there are 0 paginated threads
  • 84,919 rows already have a non-empty SQLite preview, so the state index itself is substantially populated
  • rollout storage is approximately 29 GiB across about 84,987 JSONL files
  • largest active rollout is about 236 MB; largest archived rollout is about 371 MB
  • during the reported slow-open state, the app-server was observed around 142% CPU and 3.4 GiB RSS; one renderer was about 3.1 GiB RSS

The local log database also preserves a prior Desktop replay burst on the same profile. For one valid legacy thread with 9,978 reconstructed items and zero parse errors, thread/turns/list completed 4-5 full reconstructions per second for multiple consecutive seconds. A second thread was being reconstructed concurrently. This is stronger than a single slow resume: identical page requests were multiplying whole-rollout work.

Packaged-client and current-source path

I unpacked the installed app.asar and traced task opening. The client requests thread/resume with excludeTurns plus initialTurnsPage when supported, but legacy fallback still calls thread/read(includeTurns: true) when that page is unavailable. It also has multiple metadata/status polling paths using thread/read(includeTurns: false) and thread/turns/list.

Current main still documents the server-side cost explicitly: legacy thread/turns/list calls load_thread_turns_list_history, then "replays the entire rollout on every request" until turn metadata is indexed separately:

The newer paginated-history path does not help an existing profile where every thread is legacy. That explains the observed behavior: page-sized network responses still require O(total rollout bytes/items) parse and reconstruction, and concurrent/repeated callers multiply the work.

Suggested landing order

  1. Stop polling completed/inactive threads and deduplicate identical client requests.
  2. Add app-server single-flight/coalescing for concurrent legacy history reads keyed by thread plus stable rollout identity, so one client burst cannot launch several full reconstructions.
  3. Index or safely migrate legacy turn metadata so thread/turns/list becomes true storage-level pagination rather than response-only pagination.
  4. Bound initial hydration by bytes as well as turn count, and expose a recoverable oversized-history state instead of blocking task navigation.

The direct user symptom is approximately 20 seconds to open an unread/older task. The profile remains intact for additional privacy-safe counters or testing against a candidate build.

louis030195 · 21 days ago

codex is unusable because of this, takes 30s to go from a chat to another chat, back to claude

boombx403-byte · 9 days ago

Hi @PrinnyQ, cross-platform WSL/Windows path mismatches often make healthy transcripts look broken when workspace contexts change. Codex Rescue Alpha5 explicitly separates transcript integrity from workspace path-family portability without rewriting saved paths.

If you'd like to check the local rollout safely:

pip install codex-rescue==0.1.0a5
codex-rescue doctor --latest

Please sanitize private paths before posting any output.