Repository navigation
Desktop app (macOS): idle node_repl visualization kernels accumulate (60–70 concurrent, ~600 MB), causing severe input lag #39816
Description
What happened
During normal interactive use of Codex in the ChatGPT macOS desktop app, the embedded Codex engine accumulates dozens of idle cua_node/bin/node_repl processes — the sandboxed Node kernels spawned for the visualizations feature. Within ~45 minutes of app launch I observed 67 concurrent node_repl kernels, all at 0% CPU, ~10 MB RSS each (~580–700 MB combined), each wrapped in its own codex sandbox supervisor process, so the app's total process tree reached 138 processes / ~6.5 GB RSS.
Combined with the UI renderer growing to ~1.6 GB and staying busy (~40% CPU), this produced severe keyboard input lag in the app — keystrokes visibly queue. The machine (24 GB RAM) was pushed deep into swap (5.7 GB of 6 GB used within 45 minutes of a reboot).
Kernel reaping appears to exist but is far too slow: the count drifted 67 → 60 over about a minute of idle observation, while most kernels showed elapsed times of 18–20 minutes after their originating work had completed. At least one kernel had been alive 48+ minutes — the entire lifetime of the app process — suggesting some are never reaped. During an active session the spawn rate easily outpaces the reaper.
Evidence
Process count and per-kernel detail (usernames/paths redacted):
$ ps ax | grep -c "[n]ode_repl"
67 # later 61, 60 — slow drain while idle
$ ps -axo pid,ppid,%cpu,rss,etime,command | grep "[n]ode_repl" | head
256 18253 0.0 10752 19:54 /Applications/ChatGPT.app/Contents/Resources/cua_node/bin/node_repl
7604 18253 0.0 10768 06:44 /Applications/ChatGPT.app/Contents/Resources/cua_node/bin/node_repl
8355 18253 0.0 10768 19:31 /Applications/ChatGPT.app/Contents/Resources/cua_node/bin/node_repl
8593 18253 0.0 10768 19:23 /Applications/ChatGPT.app/Contents/Resources/cua_node/bin/node_repl
14346 18253 0.0 8000 48:29 /Applications/ChatGPT.app/Contents/Resources/cua_node/bin/node_repl <-- alive since app launch
...
579 MB across 57 node_repl kernels (all 0.0 %CPU)
All kernels are children of the main codex engine process (pid 18253 above, itself at ~812 MB RSS). Each kernel also has an accompanying codex sandbox wrapper of the form:
/Applications/ChatGPT.app/Contents/Resources/codex sandbox \
-c default_permissions="node_repl" \
-c permissions.node_repl={filesystem = {..., "~/.codex/visualizations/2026/08/20/<uuid>" = "write", "<workspace dir>" = "write", ...}, network = {enabled = false}} \
-- .../cua_node/bin/node --experimental-vm-modules /var/folders/.../kernel.js --session-id <id> --working-dir <workspace dir>
The ~/.codex/visualizations/<date>/<uuid> write grants indicate one kernel per visualization/REPL artifact.
Aggregate app footprint at the time:
ChatGPT/Codex total: 244% CPU, 6.5 GB RSS across 138 procs
67 cua_node/bin/node_repl (idle kernels)
25 Codex Framework helpers (Chromium; renderer at 1.6 GB RSS, ~40% CPU, 10+ min CPU time in 42 min)
16 Resources/codex (engine + sandbox wrappers)
14 ~/.codex/computer-use/Codex
10 cua_node/bin/node
Expected behavior
Visualization kernels should be terminated promptly (seconds, not tens of minutes) once their visualization/REPL work completes, or a small bounded pool should be reused. Idle kernels should never survive for the lifetime of the app.
Impact
Severe keyboard/input lag in the desktop app during and after heavy Codex use; system-wide memory pressure (swap exhaustion) on a 24 GB machine. Fully quitting and relaunching the app clears it, which is the current workaround.
Environment
- ChatGPT macOS desktop app 26.818.22352 (6872), bundled Codex Framework 151.0.7922.170
- macOS 26.5.2 (25F84), Apple Silicon (14-core), 24 GB RAM
- No
codex execCLI runs were active — this is entirely the desktop app.
Activity
github-actions commentedon Aug 20, 2026
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
lemonluck01 commentedon Aug 24, 2026
Confirming this on macOS 26.6, ChatGPT.app 26.818.21641 (6849), Codex CLI 0.149.1.
Same symptom, two additions:
Not desktop-app-specific. Some of the leaked pairs here were children of a standalone
codexCLI process (installed via@openai/codexnpm package,/opt/homebrew/lib/node_modules/@openai/codex/...), not just ChatGPT.app's bundled Codex Framework. Different PPIDs, same leak pattern.Paired with an MCP stdio server, not just the node_repl kernel. Every leaked
cua_node/bin/node_replhad a matching orphaned MCP server process (a user-configured stdio MCP server, spawned via the same session) sitting alongside it — same lifecycle, same non-reaping. So this isn't isolated to the visualization kernel; whatever spawns/tracks per-session child processes for code-mode sessions generally isn't reaping them.Zero drain, not slow drain. Where the original report saw a slow drift (67 → 60) over ~1 minute of idle observation, mine showed literally zero reaping across multiple checks spanning the investigation — and the oldest surviving pair dated to Wednesday, roughly 4-5 days of continuous accumulation, not just one 45-minute session.
Manual
killon the matched PIDs freed ~690 MB immediately with no ill effect on the live ChatGPT app or an active CLI session — consistent with this report's workaround, just without needing a full app restart.Environment: macOS 26.6 (25G72), Apple Silicon.
Sergic commentedon Aug 28, 2026
Additional reproduction data from a later build
I can reproduce this on:
Before a full app quit/relaunch (app uptime: ~2d 13h):
cua_node/bin/node_replprocessesnode_replRSScodexprocess: ~2.4 GiB RSS and roughly 20–26% CPULarge numbers of MCP-related processes had also accumulated:
firecrawl-mcpserver-sequential-thinkingmcp-gitlabxcodebuildmcpfigma-console-mcpThe Electron sampler eventually logged
Failed to collect child process snapshotbecause it attempted to invokeps -pwith hundreds of child PIDs.After fully quitting with Cmd-Q and relaunching, the app updated from 26.818.41509 to 26.825.32147:
node_repl; process tree ~38 processes / 4.0 GiB summed RSSnode_repl; process tree 51 processes / 5.1 GiB summed RSSnode_replThe count increased during consecutive code-mode/programmatic tool calls and did not return to baseline during observation.
turn/startrouting remained fast (64–83 ms), and after relaunch there were no workspace-auth or pubsub reconnect errors, but visible UI/system lag still occurred when Codex began processing a message. This suggests the lag is local runtime/process growth rather than model or network latency.The fresh launch also produced 48 MCP startup timeouts across multiple configured servers, which may amplify the process/resource growth.
A full app quit clears the accumulated tree, but only temporarily. Archiving tasks does not affect the process leak.
belongwithme commentedon Sep 3, 2026
Additional reproduction: serial title updates still accumulate
node_replprocessesI encountered what appears to be the same issue on macOS with 16 GB of RAM.
Reproduction steps
1.set_thread_titlecall to complete before starting the next one.There was no
Promise.all, worker pool, or parallel batch execution in the final reproduction.Actual behavior
Even with strictly serial execution, the helper processes continued to accumulate:
node_replprocesses: 102node_replRSS: approximately 637 MBThis suggests that limiting concurrency only reduces the transient peak. It does not prevent the leak because some
node_replprocesses are not reclaimed after the associated tool call completes.Fully quitting Codex releases the processes, but they accumulate again after continued tool usage.
Expected behavior
After a tool call completes, its
node_replhelper should either:The number of helper processes and their total memory usage should remain bounded, especially when tool calls are executed strictly one at a time.
Additional observation
The tool call returns only a success or failure result and does not expose a process identifier or lifecycle handle. Therefore, clients cannot safely clean up the corresponding helper process without risking termination of a process still used by another task.
This reproduction indicates that the problem is not limited to parallel execution; it also occurs during sequential tool calls.
gjwang commentedon Sep 6, 2026
Confirming this on a much newer build — and the leak here is significantly worse than what's described above, so leaving a data point in case it's useful for prioritization.
Environment
152.0.7977.64codex-cli 0.153.0-alpha.5unified-computer-use@openai-bundled(manifest version26.901.20858)What happened
Left the app running in the background (not actively interacting with it) for ~24 hours. Checked the process tree and found 440 leaked child processes, not just
node_repl— the entirecua_replMCP server unit (launch.mjs+node_repl+server.mjs+ anartifact-template-pickerhelper) gets re-spawned as a fresh group roughly every 10 minutes, and none of the previous groups are ever reaped. So this isn't limited to REPL kernels from actual visualization use — it reproduces from the plugin's own idle/keepalive cycle with zero user interaction.All 440 were in
S(sleeping) state, combined CPU usage across all of them was ~7% (i.e. genuinely idle, not doing work), total combined RSS 9.2 GB. All were direct children of the maincodex ... app-serverprocess (the one hostingmcp_servers.codex_app/codex-app-tools).Unlike the original report's "slow drain" (67 → 60 over a minute of idle observation), in this case zero reaping occurred over the full 24-hour window — count only ever went up. Manually
kill-ing the whole group of 440 processes was the only way to reclaim the memory; within seconds the app-server transparently respawned a fresh single group (3–6 processes), confirming the spawn side works fine and the problem is purely on the reap/lifecycle side.Expected behavior
Same as above — idle
cua_replkernel groups fromunified-computer-useshould be terminated once their keepalive/health-check cycle completes, or the plugin shouldn't spawn a brand new group every ~10 minutes at all when there's no active REPL/visualization work outstanding.Impact
Unbounded background memory growth (confirmed multi-GB within a day) with the app merely open in the background — no active Codex usage required to reproduce. Same workaround as above: fully quitting and relaunching the app (or manually killing the leaked process group) reclaims the memory until it reaccumulates.
HashimTheArab commentedon Sep 22, 2026
Additional diagnostic data from a newer build; the controlled tests did not reproduce a worker leak.
Environment: ChatGPT desktop
26.915.31945(9922), bundled Codex0.155.0-alpha.9.2, macOS26.5.1, Apple Silicon, 36 GiB RAM.After ~19 hours of normal use across multiple tasks: 16 renderers (~3.15 GiB summed RSS), 11 CUA launchers, 11 app-tools servers, and 22
node_replworkers. RSS includes shared pages. The 11 worker groups matched startup events for persisted, unarchived tasks; hidden-thread accumulation was not established.Controlled checks: created two disposable tasks, each running one Python print command, then archived them and checked their specific worker PIDs. Both main worker groups exited; additional transient REPL workers were gone within 72 seconds of archival. A separate switch-away test retained four workers after 137 seconds, then released them on archival. No processes were manually killed.
The installed desktop bundle has a three-hour inactivity TTL and a limit of ten eligible inactive tasks before unsubscribing; active/followed tasks are excluded. The full TTL/cap was not tested.
Archive cleanup worked in these tests. Renderer memory and longer-term retention remain unexplained; this does not establish that the original issue is fixed.
0xdevalias commentedon Sep 22, 2026
One useful distinction from a current macOS Desktop 26.903.71938 / Codex 0.153.4 audit: the many
node_replprocesses were downstream of retained loaded sessions, rather than independently owned kernels. One completed non-window task'snode_repland MCP fleet exited naturally about 60 s afterthread/unsubscribewhen the caller was apparently the final owner.That workaround is not universal: four completed ordinary tasks and one completed automation all returned
unsubscribedyet remained inthread/loaded/listbeyond 60 s, indicating another hidden owner. I have not reproduced this issue's exact visualization path, so this is a candidate diagnostic/workaround rather than a claim that it fixes visualization accumulation: map a kernel to its task, protect all UI/history/agent/approval owners, unsubscribe, wait >=60 s, and confirm the exact process exits. The missing product capability is subscriber diagnostics plus an explicit unload RPC.anon5376 commentedon Sep 23, 2026
Same leftover-helper class on current macOS desktop, idle, no running thread and no built-in browser session.
App
26.915.31945(build 9922), Codex Framework153.0.8010.48,Darwin 25.4.0 arm64 arm.ChatGPT/Codex helpers still held ~3.87 GB RSS across 68 processes. That includes many leftover
cua_nodenode/node_replchildren plusSkyComputerUseServiceat ~173 MB after Computer Use / the built-in browser was already closed.Closed #47519 in favor of this thread for the helper-reaping part.
Isaac-b-ux commentedon Oct 1, 2026
Adding a data point from a newer build, where retained subagent threads look like the main driver.
Environment: ChatGPT macOS desktop, Codex Framework
154.0.8037.57, bundled app-server; macOS 26 (Darwin 25.6.0); Apple Silicon, 16 cores, 128 GB RAM.After about 24h of app uptime (one app-server process):
codex app-server, about 22.8 GB RSS. The whole ChatGPT tree was about 1,150 processes and 38 GB.SkyComputerUseClient(computer-history mcp,messages mcp,event-stream mcp),node server.mjsfor the code-review / codex-app-tools / openai-developers plugins, anmcp/server.mjs, and acua-replnode_repl. That is roughly 8 processes per thread, started whether or not the thread ever calls those tools.subagentthreads and 65 user threads, persession_meta.sourcein the rollouts.Likely cause: the desktop's inactive-thread release path only unsubscribes conversations the window resumed and owns. Subagent and agent-created threads never qualify, and the app-server only unloads threads with no subscribers, so those threads and their MCP groups live until the app quits. Plugin MCP servers are also started eagerly per thread instead of on first tool use.
Requests: (1) unload completed subagent and agent-created threads, or cap retained inactive threads; (2) start plugin MCP servers lazily; (3) add a config setting to cap loaded threads or MCP runtimes.