Codex Desktop becomes unusable on long active threads due to app-server/renderer memory and TRACE log churn
Summary
Codex Desktop becomes nearly unusable with long-running active threads, even after compaction-aware local transcript pruning.
The slowdown appears to come from the Codex app-server and renderer repeatedly handling large hot conversation state and logging large websocket/SSE response frames into logs_2.sqlite.
Environment
- Codex Desktop: 26.429.30905
- Electron: 41.2.0
- macOS: 26.0.1 (25A362)
- Machine memory: 16 GB
Observed behavior
During the slowdown:
codex app-serverspiked to ~64% CPU.codex app-serversampled physical footprint peaked at ~4.4 GB.- A Codex renderer reached ~1.07 GB RSS.
logs_2.sqlite/ WAL grew by about 1.4 MB in one second.- Recent log rows were dominated by TRACE entries from:
codex_api::endpoint::responses_websocketcodex_api::sse::responses- raw-ish response/frame logging such as
response.completed/ received websocket frames - One active long-running thread had grown back to ~839 MB with 22 compactions.
- The app remained sluggish even after pruning older pre-compaction rollout records, until restart/reload.
Chronicle was not the active CPU source in this case.
Why this seems like a Codex Desktop issue
Compaction-aware pruning helps reduce hot rollout JSONL size, but the running Desktop app still appears to keep or reconstruct very large hot thread state in app-server/renderer memory.
Separately, TRACE logging of large websocket/SSE frames can make logs_2.sqlite churn quickly, which seems to amplify the slowdown.
This makes long-running "main" threads effectively degrade over time, even when compactions exist and old raw history has been pruned locally.
Expected behavior
Long-running threads should remain usable after compaction. Codex Desktop should not need manual JSONL pruning, log rotation, or full restart to recover basic responsiveness.
Suggested fixes
- Truncate or disable large TRACE websocket/SSE payload logging in normal Desktop builds.
- Avoid retaining/rendering full hot thread state after compaction.
- Lazy-load old transcript/UI history instead of materializing the whole active thread.
- Add a first-class local "prune/compact UI history" action that preserves agent-visible compacted context.
- Release app-server/renderer in-memory thread state after compaction/pruning without requiring a full app restart.
- Add diagnostics that show which active thread/log source is causing app-server or renderer pressure.
Impact
For users who keep long-running main threads open, Codex Desktop can become almost unusable: high CPU, high renderer/app-server memory, heavy SQLite log churn, and severe UI lag.
16 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Someone investigated this in #21211 You can improve performance just by truncating titles to 120 chars in state_5.sqlite but the sidebar still loads the full first message just on launch so it's still problematic.
Adding another Windows Desktop data point that matches this issue.
Environment:
OpenAI.Codex_26.527.3686.0_x64__2p2nqsd0c76g0%USERPROFILE%\.codexObserved local DB state while the app was running:
logs_2.sqlite: ~812.9 MBlogs_2.sqlite-wal: grew to ~100 MB before checkpoint; after one successful checkpoint it dropped briefly, then grew back to ~75.7 MB during continued uselogsrows: ~180,537state_5.sqlite: ~4.36 MBlogs_2.sqlite: ~115,943 pages, about ~452.9 MB reclaimable/free pagesTop log targets by estimated bytes:
codex_api::endpoint::responses_websocket: ~101 MB / ~23k rowscodex_otel.log_only: ~33 MB / ~26k rowscodex_otel.trace_safe: ~29 MB / ~24k rowscodex_client::transport: ~24 MBExperiment:
PRAGMA wal_checkpoint(PASSIVE)followed byPRAGMA wal_checkpoint(TRUNCATE)onlogs_2.sqlitewhile Codex Desktop was open immediately reduced the perceived UI jank.This makes the issue feel like normal Desktop interaction is being affected by log DB/WAL growth and SQLite churn, not just long model latency. A built-in safe action such as "Optimize local data" / "Clear local diagnostic logs", plus automatic log rotation/checkpointing or bounded TRACE logging, would likely help users recover without manually touching SQLite files.
same issue
Another data point from Codex Desktop 0.140-alpha on Windows 11:
logs_2.sqlitereached 3.4 GB over 11 days (matches the ~10-day retention; rows pruned logically but no VACUUM, so disk stays allocated).responses_websocketalone ~1 GB), INFO 354 MB, DEBUG 57 MB. Consistent with #17320 (SQLite sink ignoringRUST_LOG).codex app-serverprocess kept the WAL open after the GUI was closed (related: #22444). Killing the orphans was required before the file could be moved..codex/skillsfile watcher fired continuously on__pycache__(.pyc temp files) and bundled-plugin cache churn — each event loggedskills cache cleared+ askills/changedapp-server event at TRACE, inflating the DB further.Mitigations that restored the app: kill orphan app-servers, move the oversized
logs_2.sqliteaside (app recreates an empty one), clear stray__pycache__. A config/env knob to cap or disable the SQLite TRACE sink would help a lot.Adding a fresh macOS data point from a current Desktop build. This looks like the same class of issue, but with both renderer CPU and app-server TRACE/log/MCP churn visible at the same time.
Environment
26.616.81150(CFBundleVersion4306)149.0.7827.115codex-cli 0.142.027.0 (26A5368g)on arm64/Applications/Codex.app/Contents/Resources/codex app-server --analytics-default-enabledObserved CPU
While the app was sluggish, repeated
pssamples showed:Earlier samples in the same run showed the renderer around
80-151% CPUand app-server around18-25% CPU.The renderer was the largest CPU consumer, but the app-server was also continuously active.
logs_2.sqlite churn
Local log DB state:
Short interval sample:
That is about
381 log inserts/sec, while the app was still running normally from the user's perspective.Recent log rows were dominated by TRACE/DEBUG/WARN entries like:
Top recent rows by target/body included repeated
session_loop{...}:submission_dispatch{...}entries undercodex_mcp::connection_managerandcodex_api::sse::responses.MCP process multiplication
At the same time, the app-server had multiple repeated direct child process groups. Sanitized count:
Most of these children were individually low CPU, but app-server was still spending CPU managing/logging the aggregate connection/event stream.
Samples
sampleon the renderer for 5 seconds:329.9M726.0Msampleon app-server for 5 seconds:267.7M278.2Mtokioworker threadssqlx-sqlite-worker-*sqlite3_stepsqlite3_wal_checkpoint_v2tracing_core::event::Event::dispatchcodex_state::log_db::MessageVisitorcodex_protocol::dynamic_tools::normalize_dynamic_tool_specstokio::fs::file::File::poll_readWhy this seems related
This looks like a combined feedback loop:
The external MCP children themselves were not the primary CPU source.
Expected behavior
Codex Desktop should not sustain
100%+renderer CPU plus30%app-server CPU while tool subprocesses are mostly idle. TRACE logging and MCP status/event streams should be bounded, filtered, batched, or deduplicated so that normal Desktop use does not continuously drive hundreds of SQLite log inserts per second.Related
This also overlaps with the SQLite TRACE churn tracked in #28224 and related follow-ups, but the user-visible symptom here is Desktop CPU/UI pressure with renderer + app-server both hot on
26.616.81150.I can reproduce what appears to be the same issue on Windows, and I isolated
logs_2.sqliteas the trigger with a local A/B test.Environment
OpenAI.Codex_26.707.3748.0_x64codex-cli 0.140.022631.5768, x64Symptoms
Creating a new task, switching tasks, or opening a history item that had not yet been opened would freeze the Codex UI for several seconds. During the worst reproductions, the stall also made the rest of the Windows desktop feel temporarily unresponsive. Restarting Codex or rebooting Windows did not resolve it.
I also tested disabling Browser/Chrome integrations, plugins/MCP servers, Figma, and
node_repl, and tested with a clean Electron UI profile. Those changes did not resolve the stall. Moving most session history was also not the decisive factor.Isolated result
The local diagnostic log database had grown to:
logs_2.sqlite: 220.23 MBlogs_2.sqlite-wal: approximately 5.63 MB at the captured pointAfter moving the 220 MB
logs_2.sqliteout ofCODEX_HOMEand allowing Codex to create a fresh log database, the task/window switching stalls disappeared immediately. Restoring normal Codex features did not bring the stalls back.This is notable because the problem occurred at roughly 220 MB, substantially below the ~813 MB database reported in the original issue. It suggests the trigger may depend on fragmentation, row count, checkpoint behavior, or local SQLite contention rather than file size alone.
Temporary workaround that worked locally
logs_2.sqlite*files fromCODEX_HOME(%USERPROFILE%\.codexby default).This did not remove conversation/session history in my test. I am not attaching the original SQLite database because diagnostic logs may contain private local paths, commands, or task data.
A built-in Clear/Rotate diagnostic logs or Optimize local data action, plus bounded retention and automatic WAL checkpoint/VACUUM behavior, would prevent users from needing to manipulate SQLite files manually.
I’m seeing a closely matching slowdown on Codex Desktop for macOS and collected read-only local diagnostics.
Environment:
26.707.91948(build5440)0.144.426.5.2(Apple Silicon)Observed while the UI felt sluggish:
sample: ~955 MB, with a recorded peak of ~3.3 GBcodex app-serverRSS: ~487 MBLocal Codex state:
~/.codex/sessions: 7.3 GB / 829 files~/.codex/archived_sessions: 3.7 GB / 449 files~/.codex/logs_2.sqlite: 1.7 GBcodex_mcp::connection_manager: ~102 MBcodex_api::sse::responses: ~82 MBcodex_core::stream_events_utils: ~51 MBImportant caveat: during a five-second idle sample, the SQLite DB/WAL did not grow and renderer CPU later settled around 1–2%. So I cannot confirm continuous write churn or a permanent CPU spin. The strongest local signal is accumulated hot thread/rendering state plus V8 GC pressure, with the large log DB potentially amplifying it.
The app had updated to this build earlier the same day, but I do not yet have an older-build control test. No local data was deleted or modified during diagnosis.
Follow-up after a full Codex Desktop restart: the UI remained very slow, so restart is not an effective workaround in this environment.
Fresh-process evidence roughly eight minutes after relaunch:
v8impl::Reference::InvokeFinalizerFromGC.codex app-serverbriefly reached ~21% CPU and ~550 MB RSS, although a later sample mostly found its Tokio workers waiting rather than a continuously hot loop.rmcp::service; other leading sources were MCP connection management and app-server outgoing-message TRACE logs.The desktop startup log also emitted repeated:
ResizeObserver loop completed with undelivered notificationsIAB_LIFECYCLE route window is not liveIAB_LIFECYCLE browser use route window missing for cursor/active stateThose Browser Use warnings referenced many existing and client-new-thread conversation IDs during startup reconciliation. They appear related to the IAB route-management issue family (for example #20678), but I cannot prove they are the primary cause of the UI lag. My current read is that they may amplify the long-thread/state-replay problem described here.
System pressure remained low: zero swap and generally high CPU idle. This makes a persistent Desktop build/state-reconciliation issue more likely than machine-wide resource pressure.
Adding a fresh Windows Desktop reproduction from the current app build. This appears to match this issue and the symptoms reported in #19923 and #20544.
Environment
26.707.12708.010.0.26200(build 26200)31.0.21925.1001(2026-05-20)32.0.16.1074(2026-02-07)Reproduction and symptoms
Privacy-safe local measurements
During a 35-second sample while opening an affected thread:
ChatGPT.exeprocess working set grew from about 356 MB to 1,784 MB.Examples of short but internally heavy local histories:
Troubleshooting already performed
The behavior remained unchanged after all of the above. The transient growth and later release of the main-process working set make this look like expensive thread-state materialization/deserialization or GC on the UI-critical path rather than a GPU-driver or machine-capacity problem.
Expected behavior: old tool outputs and image/screenshot records should be lazily hydrated or virtualized so that switching threads does not block pointer and keyboard input.
I can provide sanitized per-process samples or collect a specific performance trace if maintainers indicate which artifact would be most useful.
Adding a sanitized current-build macOS reproduction. The app did not crash during the 12-minute live capture, so the numbers below distinguish measured resource pressure from the user-reported long-task crashes.
Environment
26.715.72359(build5718) with bundledcodex-cli 0.145.0-alpha.3026.5.1 (25F80), Apple Silicon, 16 GB RAMLive measurements
event_msg/mcp_tool_call_end: 166.6 MiBresponse_item/custom_tool_call_output: 96.0 MiBcompacted/message: 85.8 MiBlogs_2.sqlitewas about 366 MiB plus WAL, with about 254k rows. High-volume classes included:codex_api::sse::responsesTRACE: 43,106 rows / estimated 44.9 MiBcodex_core::stream_events_utilsDEBUG: 21,125 rows / estimated 38.5 MiBcodex_mcp::connection_managerTRACE: 32,182 rows / estimated 27.6 MiBrmcp::serviceTRACE: 595 rows / estimated 17.2 MiBmacOS resource diagnostics from the same machine
codexdisk-write diagnostic recorded 2.15 GB of file-backed writes in 269 seconds while footprint grew from 147.8 MB to 1.97 GBInterpretation
This looks like episodic memory/I/O amplification when large histories are materialized or replayed, combined with high-volume TRACE/SSE/MCP persistence—not solely a conventional monotonic memory leak. The largest rollout is dominated by tool/MCP outputs and compacted history, which also corroborates #24948, while the user-visible impact matches this Desktop renderer/app-server issue.
Useful acceptance criteria would be:
Adding a sanitized Windows reproduction from the current Desktop build. The behavior started after the recent update and the app now intermittently terminates/restarts.
Environment
OpenAI.Codex_26.721.4979.0_x64codex.exe -c features.code_mode_host=true app-server --analytics-default-enabledDirect measurements
logs_2.sqlite: approximately 568 MBlogs_2.sqlite-wal: approximately 305 MBcodex_app_server::outgoing_messageandcodex_api::sse::responses.The local configuration uses supported settings and does not explain an app-server allocation of this magnitude. No personal paths, thread contents, or unsanitized logs are included here.
This is especially frustrating on a paid plan costing approximately EUR 220/month: the Windows Desktop application is currently not dependable enough for sustained work.
I can collect additional privacy-safe counters or a specific diagnostic trace if maintainers provide instructions.
I can reproduce substantial
codex app-servermemory growth on the same Windows build reported here.Environment
OpenAI.Codex_26.721.4979.0_x6426.721.410590.146.0-alpha.3.1codex.exe -c features.code_mode_host=true app-server --analytics-default-enabledMemory observations
During active use, app-server private memory increased from approximately 1.00 GiB to 1.87 GiB in about seven minutes and briefly reached approximately 1.92 GiB. It later fell to approximately 1.72 GiB, so this short sample does not prove strictly monotonic leakage, but app-server was clearly the dominant Codex process.
Historical Windows Resource Exhaustion events from an earlier
26.715session showcodex.exereaching approximately 6.17–6.71 GiB after many hours, plus 1.43–1.63 GiB in the Electron process.Logging observations
~/.codex/logs_2.sqlitecurrently contains approximately:The largest contributors are HTTP transport, SSE responses, and stream-event logging. Roughly 89.6 MB of HTTP transport logs and 63 MB of SSE logs were added during the most recent 24-hour window.
The public log sink appears to use a queue bounded by entry count rather than bytes (512 entries, batches of 128). With multi-megabyte entries, this could temporarily retain hundreds of MiB or more, with additional copies created during formatting and SQLite insertion. Allocator high-water behavior could then keep app-server private memory elevated after the queue drains.
The database quota also appears to be approximately 10 MiB per thread rather than a comparable global limit, allowing aggregate storage and maintenance work to scale with the number of tasks.
Thread cleanup
The Desktop bundle does implement inactive-thread cleanup: one-hour TTL, no more than four inactive owner threads, followed by
thread/unsubscribe. I found eight successful unsubscribe events in a long session, so this does not appear to be a simple case where no threads are ever released.Overall, the evidence looks more like large-payload logging plus thread/history retention and transient duplication than one simple monotonic leak.
Would it make sense to:
Fresh Windows reproduction on the current stable Microsoft Store build adds a fairly strong renderer-side A/B data point.
Environment
The public stable Windows update manifest also reported
26.721.4979.0, so no newer stable build was available during the test.Symptom
Typing in the composer lagged behind keystrokes while one long-running remote/WSL task was actively streaming events. The rest of Windows remained responsive.
System-wide exhaustion was ruled out during the incident:
The primary Electron renderer was the clear local hot process:
This looked like sustained allocation/GC churn rather than system RAM pressure or an OOM condition.
Renderer-state evidence
Sanitized counts from the current day's Desktop logs:
One representative hour contained:
The event volume was dominated by the one active long-running task and its related work. Its local rollout was only about 45.5 MB, so this reproduced well below the several-hundred-megabyte histories reported in some related issues.
A previously diagnosed WSL repository-watcher loop was explicitly ruled out in the fresh logs:
The active projects were already registered through the native remote WSL host with Linux paths, rather than Windows UNC paths.
Recovery A/B
I recycled only the overloaded primary renderer. The installed app's own
render-process-gonehandler reloaded the window after 500 ms; the Electron main process and the active remote task both remained alive.After initial history/event replay, the replacement renderer settled at:
Composer responsiveness recovered immediately. This strongly separates the UI lag from model/service latency, disk pressure, GPU load, and the remote task runtime itself. The backend task could keep running normally while a clean renderer remained responsive.
Suspected failure mode
A long-lived renderer appears to lose synchronization with live conversation/turn/item state. It then continues accepting and logging events for missing conversations or turn items. Processing/dropping those events creates sustained allocation and GC pressure on the same renderer responsible for the composer, causing delayed typing.
This seems closely related to #24263 and the state/ownership section of #25779, while #34450 captures the Windows input-lag symptom.
Requested behavior
Raw logs and local rollouts are not attached because they may contain private prompts and filesystem paths. Sanitized targeted diagnostics can be provided if maintainers specify the fields needed.
This is also blocking the main Pro workflow I want to use: keep several mature project chats alive, switch among them quickly, and delegate new tasks as priorities change. The $200/month plan is a great value in terms of capacity, but repeated thread hydration makes that capacity difficult to use—switching back to a long-running project can stall long enough that managing several in parallel becomes impractical.
Please treat fast multi-thread switching as a core workflow, not an edge case. Ideally, switching should load metadata plus a bounded recent tail immediately, lazy-load older UI history and heavy tool payloads, and keep compacted agent context ready without rehydrating the full rollout. One large or old project should never block the composer or make other project chats unresponsive.
Even when hydration must continue in the background, the text-entry field should remain independently responsive: it should keep accepting and preserving every keystroke while the rest of the thread loads or hangs. By the time I finish typing, hydration may already be complete—but currently hydration freezes the composer itself, sometimes triggering the Windows “program is not responding” dialog while I am typing and creating a risk of accidentally killing the app or losing the draft. Ideally the composer/draft state would be isolated from heavy thread rendering and loading, with only submission waiting when strictly necessary.
<details>
<summary>Sanitized local evidence from one occurrence (Windows Desktop 26.727.51351)</summary>
All times below are local; thread IDs, turn IDs, paths, workspace names, account data, and message contents are omitted.
These two events were post-restart, while typing and while startup restoration/hydration was still active. In the first 68 seconds after restart, the renderer requested
skills/list8 times andplugin/list4 times. In the 150 seconds before restart, it requestedthread/turns/list13 times andskills/list9 times.The mature rollout involved in the switching investigation was 314,596,334 bytes (about 300 MiB) with 32,515 JSONL records. During the surrounding 15-minute app-server log window there were 504 rows, including 54
codex_core_skills::loaderwarnings, 38codex_core_plugins::manifestwarnings, and 4codex_app_server::request_processors::thread_processorwarnings. No disk or storage-controller errors were found in the same incident window.A separate pre-restart symptom occurred in the same session: a
turn/startrequest did not create an active/durable turn while Desktop and mobile displayedThinking. That turn-lifecycle stall is not the mid-typing composer hang described above; it is included only as nearby state-desynchronization context.</details>
Adding a fresh sanitized Windows reproduction from the current stable Desktop package.
Environment:
OpenAI.Codex_26.803.5235.0_x64Privacy-safe process snapshots from the installed observe-only watchdog:
codex.exeapp-server: 307.7 MiB.Local diagnostic DB, queried read-only while the app was running:
logs_2.sqlite: 467,456,000 bytescodex_api::sse::responses: 1,983 rows / 2.15 MBcodex_core::stream_events_utils: 1,650 / 1.89 MBcodex_app_server::outgoing_message: 913 / 0.16 MBfeedback_tags: 809 / 1.24 MBA bounded tail scan of 12 local diagnostic log files found 0
unknown conversation eventmatches in the scanned tails. The current day's sandbox log also had 0 new os-error-206 matches in its last 400 lines after switching away from the previously broken elevated helper path. Therefore this occurrence does not require an unknown-event storm or sandbox-helper failures; long-thread event materialization plus TRACE/SSE persistence remains sufficient to reproduce typing lag and sustained renderer/app-server growth.The local watchdog is event-first, observe-only, and performed 0 process reclaims / 0 app restarts. It records sanitized memory/process evidence but cannot repair the packaged renderer/app-server. This fresh build still needs bounded/lazy thread hydration, byte-bounded TRACE logging, and renderer-state release without a full app restart.
No raw thread content, IDs, prompts, paths, command lines, credentials, or log bodies are included.