Repository navigation
Codex for macOS accumulates Computer Use / MCP helper processes and unreaped zombie children, causing HID lag and WindowServer/TCC stalls #25744
Description
Codex macOS Resource Leak / Unreaped Child Processes Report
GitHub Issue Draft
Title
Codex for macOS accumulates Computer Use / MCP helper processes and unreaped zombie children, causing HID lag and WindowServer/TCC stalls
Summary
On macOS, a long-running Codex session accumulated a large number of Codex-owned helper processes related to Computer Use / MCP tooling. The machine became visibly laggy. Inspection showed:
- Dozens of live
SkyComputerUseClient mcpprocesses. - Dozens of live
node_replprocesses. - Dozens of live
codex app-server --listen stdio://helper processes. - More than 100 zombie child processes whose parent was the main Codex GUI process.
- macOS spin reports for Codex showing slow HID event handling, with WindowServer blocked in the TCC event-monitor permission path.
Manual cleanup of stale helper processes reduced live Codex-related memory use by roughly 3 GB, but the zombie processes could not be cleared without restarting Codex because the main Codex process did not reap them.
Related Issues
This may share root cause with MCP stdio lifecycle leaks such as #17832, but this report adds a separate Computer Use case with SkyComputerUseClient accumulation, Codex-owned zombie children, and macOS WindowServer/TCC HID stalls. It does not look like the SkyComputerUseClient code-signing crash in #21200 or the simple unexpected-exit case in #18549.
Environment
Sanitized system details:
- App: Codex for macOS
- Codex version:
26.527.31326 - Codex bundle version:
3390 - Codex bundle ID:
com.openai.codex - Chromium base:
148.0.7778.179 - Computer Use app bundle ID:
com.openai.sky.CUAService - Computer Use app version:
1.0 - Computer Use build:
799 - Computer Use client bundle ID:
com.openai.sky.CUAService.cli - Computer Use client version/build:
1.0 (799) - OS: macOS
26.5build25F5042g - Architecture: Apple Silicon /
arm64 - CPU: Apple M-series Pro class, 14 logical CPUs
- Memory: 24 GB
- Thermal state: no thermal or performance warning recorded during sampling
Privacy redactions applied:
- User home path replaced with
<HOME>. - Host/device name redacted.
- Project/workspace paths omitted.
- Unrelated app/process names omitted unless directly relevant.
- Raw spin report should not be attached unless separately redacted; it contains a full process inventory.
Observed Behavior
The main Codex process stayed alive for approximately 16 hours. During that period, helper processes accumulated rather than being cleaned up.
Initial process counts observed:
SkyComputerUseClient count=50 cpu=18.0% mem=4.7% rss=1448.1 MB
node_repl count=47 cpu=0.0% mem=0.0% rss=405.3 MB
codex app-server stdio count=47 cpu=3.2% mem=6.3% rss=1715.4 MB
Codex app/server/renderers count=several, additional RSS/CPU
Aggregate Codex-related footprint before cleanup:
codex_related count=143-144
codex_related RSS ~= 4.8-4.9 GB
codex_related CPU ~= 28-70% depending on sample
Zombie processes:
zombies=126
parent=<codex-main-pid> zombies=126
After killing stale helper processes, the zombie count increased slightly rather than disappearing:
zombies=128
parent=<codex-main-pid> zombies=128
That strongly suggests the main Codex process is not reaping exited child processes.
System Symptoms
The machine was visibly laggy. System-level sampling showed:
Load Avg: 8.12 6.57 6.23
Processes: 980 total
Threads: 6301
CPU usage: 13.70% user, 22.98% sys, 63.30% idle
PhysMem: 22 GB used, 1.3 GB unused
Compressor: ~5.5 GB
Memory pressure: not critical
Thermal warnings: none
The strongest live CPU consumers during the bad state included:
trustd ~90-100% CPU in multiple samples
syspolicyd ~20-60% CPU in multiple samples
WindowServer ~40-50% CPU in multiple samples
Codex GPU ~8-40% CPU depending on sample
Codex renderer/app server also periodically high
After helper cleanup, trustd and syspolicyd dropped back to low single-digit CPU in later samples. This suggests the large helper-process population may have been amplifying code-signing/trust/TCC work.
macOS Spin Report Evidence
macOS generated at least two Codex-related spin reports during the session.
Recent spin report summary, sanitized:
Date/Time: 2026-05-31 17:51:29 local time
OS Version: macOS 26.5 (Build 25F5042g)
Reason: Slow response to HID event
Command: WindowServer
Affected Process: Codex [<codex-main-pid>]
Event: spin
Duration: 2.98s
Duration Sampled: 2.77s
Steps: 277 (10ms sampling interval)
Report threshold: 0.5s
Active CPUs: 14
Memory size: 24 GB
Memory pressure: average 40%, highest 42%
Available memory: average 14.26 GB, lowest 13.75 GB
HID Events: LeftMouseDown*, LeftMouseUp
The heaviest stack for the target process was in WindowServer waiting on TCC event-monitor access checks:
WindowServer
SLXServer
server_loop
CGXRunOneServicesPass
post_port_data
rendezvousHandler
CGXHandleMessageWithResponseBuffer
_XGetEventShmem
WSEventSourceCreateGraphShmemForAuditToken
WSAuditTokenCanMonitorEvents
WSAuditTokenHoldsCachedProcessRight
audit_token_check_tcc_access
TCCAccessPreflightWithAuditToken
TCCAccessRequest
tccd_send_message
xpc_connection_send_message_with_reply_sync
dispatch_mach_send_with_result_and_wait_for_reply
mach_msg2_trap
The slow HID event line:
CGXGetNextEvent 1-274 3000.000ms WindowServer thread
There was another earlier Codex spin report the same day:
Affected Process: Codex
Event: spin
Duration: 1.28s
WindowServer stack again included kTCCServiceListenEvent / TCC preflight path
Nearby TCC logs also showed repeated privacy preflights for screen/event access by a non-Codex screen/window utility. That may have amplified the symptom, but it does not explain the Codex-owned process leak or the Codex-owned zombies.
Cleanup Experiment
The session was kept alive by not killing:
- The main Codex GUI process.
- The main Codex
codex app-server --analytics-default-enabledprocess.
Stale helpers were terminated carefully:
Killed 40 stale SkyComputerUseClient mcp processes.
Killed 80 stale node_repl / codex app-server --listen stdio:// helper processes.
Killed 1 stale SkyComputerUseService process.
Killed several old orphaned Codex crash/keyboard helper processes from previous app launches.
After cleanup:
codex_related count ~= 15-18
codex_related RSS ~= 1.8-1.9 GB
SkyComputerUseClient herd gone
node_repl / stdio helper herd gone
trustd / syspolicyd CPU substantially lower
zombies still present under main Codex process
A single fresh helper triad later respawned:
node_repl
SkyComputerUseClient mcp
codex app-server --listen stdio://
That may be the active/current session helper set. The bug is not that one helper set exists; the bug is that many old helper sets accumulated and were not cleaned up.
Expected Behavior
Codex should:
- Keep at most the necessary active helper processes for currently active tools/sessions.
- Tear down stale
SkyComputerUseClient,node_repl, and stdiocodex app-serverhelpers after a tool/session completes. - Reap exited child processes so zombie children do not accumulate.
- Avoid triggering system-wide TCC/trust/code-signing churn due to stale helper population.
- Avoid causing WindowServer HID stalls when Computer Use/event-monitor permissions are involved.
Actual Behavior
Codex accumulated:
- Approximately 50 Computer Use client processes.
- Approximately 47
node_replprocesses. - Approximately 47 stdio
codex app-serverchildren. - 126+ zombie children owned by the main Codex process.
The system became laggy and macOS generated Codex spin reports involving WindowServer/TCC event-monitor checks.
Repro / Diagnostic Commands
These are safe commands to run locally. Redact output before posting publicly.
Count Codex-related helpers:
ps -axo pid,ppid,pgid,stat,%cpu,%mem,rss,etime,args |
awk '/Codex|SkyComputerUse|node_repl|codex app-server/ {print}'Aggregate Codex-related footprint:
ps -axo pid,ppid,pgid,stat,%cpu,%mem,rss,etime,args |
awk '/Codex|SkyComputerUse|node_repl|codex app-server/ {
cpu += $5; mem += $6; rss += $7; n++
}
END {
printf "codex_related count=%d cpu=%.1f mem%%=%.1f rssMB=%.1f\n",
n, cpu, mem, rss/1024
}'Count zombie children by parent:
ps -axo stat,ppid |
awk '$1 ~ /^Z/ { z++; p[$2]++ }
END {
print "zombies=" z+0
for (ppid in p) print "parent", ppid, "zombies", p[ppid]
}'Inspect top CPU processes:
ps -axo pid,ppid,%cpu,%mem,rss,etime,args |
sort -nrk3 |
head -30Sanitize paths before sharing:
sed -E 's#/Users/[^/]+#<HOME>#g; s#[[:alnum:]_.-]+_2026-[0-9-]+-[0-9]+_[^./]+\\.spin#<redacted-spin-file>.spin#g'Workaround
The clean workaround is to quit and reopen Codex. That should clear:
- Live stale helpers.
- Zombie processes owned by the old Codex parent.
If keeping the current session alive is required, stale helper processes can be killed manually, but this does not clear zombies because the main Codex process still fails to reap them. Killing children may actually increase the zombie count until Codex is restarted.
Suggested Fix Area
Likely areas to inspect:
- Lifecycle ownership for Computer Use MCP client processes.
- Lifecycle ownership for per-session
node_replprocesses. - Lifecycle ownership for stdio
codex app-server --listen stdio://child processes. - Child-process reaping in the main Codex macOS process.
- Cleanup path when a thread/tool session ends, errors, times out, or is superseded.
- Interaction between Computer Use/event-monitoring permissions and TCC preflight calls.
Severity
High for long-running desktop sessions:
- Causes visible system lag.
- Accumulates multiple GB of resident memory.
- Creates unreaped zombie children.
- Triggers macOS spin reports.
- Involves WindowServer/TCC HID event stalls, so user input latency is affected.
Notes For Maintainers
I can provide raw spin reports privately if needed, but they contain a full process inventory and local paths. The issue body above intentionally omits those details while preserving the relevant stack, counts, versions, and cleanup experiment.
Activity
github-actions commentedon Jun 2, 2026
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
syspolicyd/trustdCPU and memory runaway #25719Powered by Codex Action
quasa0 commentedon Jun 2, 2026
Reviewed the suggested duplicates. I do not think this is an exact duplicate.
Closest is #25719 because it also involves macOS
syspolicyd/trustdpressure around Codex Desktop / Computer Use. This issue adds separate lifecycle evidence: accumulatedSkyComputerUseClientprocesses, duplicatenode_repl/codex app-server --listen stdio://helpers, 126+ Codex-owned zombie children, and WindowServer/TCC HID spin reports.The Windows/Linux MCP issues (#25697, #24347, #25742) look related at the lifecycle class level, but this report is specifically macOS Codex Desktop + Computer Use + unreaped children. #25667 is also adjacent, but focuses on
code_sign_clonetemp dirs after quit.johnsilvavlogs commentedon Jun 7, 2026
Adding current-build evidence from another macOS machine. This still reproduces on the current Sparkle appcast build and looks like the same lifecycle/perf class as this issue, with one extra signal: repeated
AppServerConnectioninitialize/reconnect failures while Computer Use MCP helpers fan out during ordinary tool discovery.Environment:
26.602.40724, bundle build359326.602.40724/3593, publishedFri, 05 Jun 2026 17:00:22 +0000codex-cli 0.135.0computer-use@openai-bundled 1.0.809com.openai.sky.CUAService, version/build1.0 (809)26.3build25D125,arm64Negative checks:
~/.codex/config.toml.SKY_CUA_SERVICE_PATHpoints at<HOME>/.codex/plugins/cache/openai-bundled/computer-use/1.0.809/Codex Computer Use.app.state_5.sqliteandlogs_2.sqliteboth passpragma integrity_check.com.openai.codexandcom.openai.sky.CUAService.Current process inventory, without restarting/killing Codex:
The oldest Computer Use MCP/helper family was ~71 minutes old; two more were ~35-36 minutes old; newer helper families appeared during this diagnostic even though no Computer Use desktop action was invoked. That suggests the Computer Use MCP process is being started as part of tool listing/session setup, not only as part of actual Computer Use actions.
High-signal log evidence:
Earlier in the same long-running app session:
There is also a Computer Use MCP protocol-compat warning in the SQLite logs:
I think the user-visible symptom is "Computer Use feels flaky", but the local root-cause shape looks broader:
This does not look like the plugin-missing issues (#18258, #21579, #26429) on this machine. It looks closer to this issue plus the app-server/MCP timeout family.
0xdevalias commentedon Jun 11, 2026
Feedback ID / Bug Report ID:
019eb57d-d318-78f2-8c45-76dea130046dA brief summary of what seems to be related issues that I just noticed due to my system being at its process limit, so failing to even run programs anymore:
The most important maintainer-facing points (according to Codex, GPT 5.5 (high)) are:
Summary of seemingly related issues by Codex (GPT 5.5, high) while reviewing this:
gitprocess spawning → OOM when the workspace is on a slow / change-notification-limited filesystem (e.g. WSL/mntdrvfs) #26904Other potentially useful/relevant threads for maybe more context:
syspolicyd/trustdCPU and memory runaway #25719Full overview / summary of everything tried/explored as per Codex (GPT 5.5, high):
Codex Desktop zombie-process accumulation and macOS process-table exhaustion
Executive summary
On June 11, 2026, a long-running Codex Desktop process on macOS had accumulated
approximately 9,940 unreaped zombie children. The zombies consumed nearly all
of the per-user process-table allowance:
This directly caused ordinary process creation to fail:
The evidence establishes that:
of process slots and did not remove the zombies.
SIGCHLD, including afterSIGCONT, did not make Codex reap them.the zombie count was zero.
The evidence does not establish:
the exited children only as
<defunct>;count was measured immediately after restart with almost no subsequent use;
node_repl, Computer Use, or stdio app-server helpers werenecessarily the zombie source, although their accumulation makes them
plausible lifecycle-related contributors.
This is best treated as a severe additional reproduction of
openai/codex#25744, with a
stronger demonstrated impact: complete per-user process-table exhaustion.
Environment
Public-safe environment details:
Redactions used below:
PIDs are retained where useful because they are ephemeral and essential for
understanding parent-child relationships.
Timeline and observations
1. Initial process-limit diagnosis
The first diagnostic set checked OS details, launchd/kernel limits, process
counts by user, and process counts by executable.
Command:
Relevant output:
Interpretation:
kern.maxprocperuid.2. Identification of the zombie parent
Command:
Relevant output:
The parent was then identified:
Output:
Direct-child sampling:
Representative output:
The oldest sampled zombies were almost as old as the Codex process itself.
This indicates gradual accumulation across the long-running app session rather
than a single recent burst.
At this point even a simple diagnostic pipeline failed:
3. Killing live helper processes did not solve the limit
Dozens of live Codex-related backend/helper processes were manually terminated.
The follow-up checks were:
Relevant output:
Live helper counts had dropped substantially:
Interpretation:
wait()/waitpid(), or by the parent exiting.The top-zombie-parent check made the concentration explicit:
Relevant output:
The few one-zombie
node_replparents were negligible compared with theapproximately 9,936 zombies directly parented by the main GUI process.
4.
SIGCHLDdid not trigger reapingCommands:
Output:
Retry after continuing the process:
Output:
Interpretation:
SIGCHLD.main process exit or injecting reaping behavior into it.
5. Final pre-restart snapshot
The saved
codex-zombie-process-snapshot.txtwas captured later in the samebad state.
Relevant output:
The snapshot also showed live Codex-related helpers:
This is useful supporting context, but the zombie command names had already
collapsed to
<defunct>, so it cannot prove that any of these helper classeswere the exited children represented by the zombie entries.
6. Main-process sample
Command:
sample 19100 10 \ -file ~/Desktop/codex-main-zombie-parent-sample.txtSample metadata:
The sampled main thread and many workers were predominantly waiting in
event-loop primitives such as
mach_msg2_trap,kevent, anduv_run.No
waitpid,wait4,SIGCHLD, child-exit, or explicit reaping stack wascaptured.
This sample is not proof of the missing code path: a 10-second statistical
sample cannot prove that a function never runs. It does show that no active
reaping loop was observed while nearly 10,000 zombies were pending.
The 10.6 GB process footprint is independently notable, but zombies themselves
do not account for that memory. Memory retention and child reaping should not
be conflated without more profiling.
7. Saved unified-log exports
Two log exports were saved:
The commands used were:
and:
Review result:
The exports contain thousands of ordinary Codex/macOS framework messages, but
no direct spawn-failure line matching the predicates above.
This negative result matters:
ps,kern.maxprocperuid, and the shell's fork failure;Codex spawn exception;
account-service activity, and other private system context, so it should not
be attached publicly without heavy redaction.
8. Session-preservation note
codex-session-restore.txtwas saved before restart to preserve a manual listof open Codex windows and thread URLs. It contains 12 thread identifiers and
project/task titles.
It explains why preserving the running app initially mattered, but it does not
identify the leak. The raw file should not be posted because thread IDs,
workspace topics, and project names are private.
9. Update/restart recovery
The Codex update changed the main process from PID
19100to PID72552.Commands:
Relevant output:
The post-restart attachment summarized in the shared chat additionally reported:
Interpretation:
26.608.12217fixed recurrence,because the replacement process had just started and had barely been used.
Root-cause assessment
Proven
The main Codex GUI process failed to reap thousands of exited direct children.
Those zombie entries accumulated over an approximately 11-day app lifetime and
eventually exhausted
kern.maxprocperuid.At the OS level, the missing invariant is:
Strongly suggested, but not proven
The broader Codex helper lifecycle likely contributes to the rate of child
creation:
codexresource processes and 73node_replprocesses were live beforemanual cleanup.
node_repl, Computer Use client, andComputer Use service processes.
notification-helper fanout.
However, the original executable identity of each zombie is unavailable.
Therefore the public report should say these helper families are plausible
sources or adjacent lifecycle symptoms, not confirmed identities of the
approximately 9,940 zombies.
Separate adjacent failure modes
The following should remain conceptually separate unless further evidence links
them:
launchdwithPPID=1;EMFILE;gitprocess spawn storms caused by watcher/retry loops.They may share ownership and teardown weaknesses, but they consume different OS
resources and require different direct fixes.
Reproduction and monitoring commands
Compact diagnostic snapshot
Run while the problem is present:
{ echo "== OS ==" sw_vers uname -a echo echo "== process limits ==" launchctl limit maxproc sysctl kern.maxproc kern.maxprocperuid echo echo "== process counts by user ==" ps -axo user= | sort | uniq -c | sort -nr | head -10 echo echo "== total zombie count ==" ps -axo stat= \ | awk '$1 ~ /^Z/ { n++ } END { print n+0 }' echo echo "== top zombie parents ==" ps -axo pid=,ppid=,stat=,etime=,command= \ | awk '$3 ~ /^Z/ { z[$2]++ } END { for (p in z) print z[p], p }' \ | sort -nr \ | head -20 \ | while read count ppid; do printf "%6s zombies PPID=%s " "$count" "$ppid" ps -o pid=,ppid=,stat=,etime=,command= -p "$ppid" 2>/dev/null done echo echo "== Codex-related live processes ==" ps -axo pid=,ppid=,pgid=,stat=,etime=,command= \ | awk '/Codex|codex|node_repl|SkyComputerUse/ { print }' }Redact the username, host name, home paths, workspace paths, thread IDs, prompt
payloads, and unrelated processes before posting.
One-shot current Codex check
Long-running recurrence monitor
This version refreshes the PID each iteration, so it survives app updates and
restarts:
Safer emergency recovery near the process limit
When pipelines can no longer fork, use shell builtins:
If the process does not exit:
SIGCHLDwas tested in this reproduction and did not recover the zombies.Raising
maxprocwould only postpone exhaustion and is not a real fix.Issue relevance assessment
Directly relevant
#25744: macOS Computer Use/MCP helpers and unreaped zombies
URL: #25744
Relevance: Direct and strongest match
Why:
node_repllifecycle context;This reproduction adds:
kern.maxprocperuidexhaustion;forkfailure;SIGCHLDrecovery experiment;Posting recommendation: Post the comprehensive overview here. This should
be the canonical location.
#12491: GUI MCP children not reaped after task completion
URL: #12491
Relevance: Direct historical precedent
Why:
25D125is explicitly represented in the issue;Important difference:
original reported bug was fixed;
Posting recommendation: Do not add the full report to this closed issue.
Link to it from the #25744 overview as prior evidence that a similar failure
class existed and may have regressed or remained in another lifecycle path.
Tangentially relevant
#26293:
SkyComputerUseClient turn-endedhelpers remain as PPID=1 orphansURL: #26293
Relevance: Adjacent and potentially related, but different observed state
Similarity:
Difference:
SkyComputerUseClient turn-endedprocessesorphaned to
launchdwithPPID=1;<defunct>children still ownedby the live main Codex GUI process;
argv detail to prove they were
turn-endedhelpers or the zombie source.Posting recommendation: Do not duplicate the full report. Add a short
cross-link only if a fresh process capture independently confirms lingering
SkyComputerUseClient turn-ended ...processes. Otherwise, mention #26293 inthe canonical #25744 report as an adjacent lifecycle path.
#26327: Windows helper-stack accumulation
URL: #26327
Relevance: Cross-platform lifecycle analogy
Similarity:
node_repl, MCP, and nested stdio app-server stacks;Difference:
precise enough.
Posting recommendation: Do not post there. A brief mention in #25744 is
enough if cross-platform context is useful.
#26984: MCP stdio pipe-FD and orphan leakage
URL: #26984
Relevance: Related ownership/teardown class, different exhausted resource
Similarity:
Difference:
EMFILE/ file-descriptor exhaustion;npm/npxdescendants;EAGAIN-style process-table exhaustion caused byzombies under the Desktop GUI process;
Posting recommendation: Do not post the overview there. Link it from
#25744 only as a possible shared lifecycle class. Comment on #26984 only if a
future reproduction also captures monotonically increasing Codex-owned pipe
FDs with
lsof.Likely not relevant
#26904: WSL slow-filesystem git spawn storm
URL: #26904
Relevance: Likely unrelated root cause
Why:
/mntdrvfs trigger;gitprocesses spawned faster than they finish;ENOSPCand retry/backoff behavior;The only commonality is the eventual exhaustion caused by unbounded process
lifecycle behavior.
See Also
0xdevalias commentedon Jun 11, 2026
I have now identified one concrete source of Codex-owned zombie bursts and filed the implementation-specific report as #27570:
review-summaryspawns thousands ofgit hash-objectprocesses when nested repositories are present #27570In a prospective process trace, opening/switching older threads caused the main Codex GUI process to spawn exactly 5,042 direct:
children. The zombie count reached exactly 5,042 before the children were eventually reaped.
Inspection of the installed Desktop bundle identified an unbounded fallback in the
review-summaryGit worker:git hash-objectcall.fatal: Unable to hash (null).Promise.all.This provides a confirmed Git-based source for transient main-GUI-owned zombies. It may explain some or all of the approximately 9,940 long-lived zombies previously documented here, but that historical connection remains unproven because their executable identities were already lost.
Nicolas0315 commentedon Jun 22, 2026
Adding a current verification snapshot from another macOS Codex.app session (2026-06-22 JST).
Environment:
com.openai.codexcodex-cli 0.142.0-alpha.6codex-cli 0.141.0~/.codex/app-server-control/app-server-control.sock, parent process/Applications/Codex.app/Contents/Resources/codex app-server --analytics-default-enabledcomputer-use,event-stream, andnode_replenabled;onepassworddisabledCurrent observation, without restarting or killing Codex:
SkyComputerUseClient event-stream mcp: 19 processes, oldest sampled process about 16h oldSkyComputerUseClient mcp: 19 processes, oldest sampled process about 16h oldnode_repl: 21 processes, oldest sampled process about 16h oldnode_replreset and JS call currently succeeds, so this is not the immediatesandboxPolicymissing-field failure mode.Health checks:
codex doctor --jsoninitially reported the app-server socket as stale/unreachable with a 2s probe timeout.codex app-server daemon version, a second doctor run reportedapp_server.status=ok.overallStatus=failonly because this noninteractive environment hasTERM=dumb.Repro / verification commands used:
Interpretation:
This looks like the same helper lifecycle / fan-out class as this issue, not a new distinct issue. A useful fix invariant would be that old per-session Computer Use /
node_replhelper families stay bounded or are reaped while the long-lived app-server remains alive.dysthymia commentedon Jun 25, 2026
Adding a fresh sanitized macOS Codex.app crash/stackshot data point that looks like the same lifecycle/resource-leak class, but with a more severe end state:
WindowServerwas terminated by watchdog after a Codex-ownednodeprocess storm.Environment:
26.616.81150, bundle build4306Darwin 25.5.0 arm64 arm26.5.1build25F80What happened:
last rebootshowed the machine did not actually reboot; uptime was still about 22 days.WindowServerstackshot / bug type409.WATCHDOG, indicatormonitoring timed out for service.Most relevant stackshot numbers, redacted and aggregated:
Largest processes in the Codex coalition:
This seems important because the biggest signal was not only Codex renderer memory. The stackshot had more than a thousand
nodechildren/related processes grouped into the same Codex jetsam coalition. That matches the helper-process accumulation pattern reported above, but the observed impact reached a system UI watchdog termination.Other context:
Expected behavior:
node,node_repl, or app-server helper processes across a long-running desktop session.WindowServerwatchdog reset.Useful local diagnostic commands for future reports:
I intentionally omitted raw paths, usernames, project/workspace names, third-party project identifiers, display/peripheral names, and the raw stackshot process inventory.
Nicolas0315 commentedon Jun 28, 2026
Adding a current helper-accumulation datapoint from the latest macOS Desktop build I have installed.
Snapshot time: 2026-06-28 11:26 JST
Environment:
26.623.42026, build45140.142.3Current sanitized helper counts:
Selected app-server FD counts from the same snapshot:
This looks like the same lifecycle class as this issue, with one extra angle: in a multi-surface setup where Codex Desktop, CLI, VS Code, and Cursor are all present, the shared MCP/tool configuration appears to multiply the same helper families across surfaces. I did not kill or restart anything before collecting these numbers.
Omitting raw process args, full local paths, and private project/tool details here.
clairernovotny commentedon Jun 29, 2026
Adding a narrower source-level repro for the app-server/MCP helper retention path. This is from a current local
openai/codexcheckout, with local paths sanitized.The live symptom was not just macOS FD pressure. Once the long-running app-server accumulated repeated MCP/helper runtime groups, new Codex unified exec process creation started failing with:
At the same time, an already-live Node MCP runtime could still spawn
/bin/pwd, so the failure was not a global OS inability to fork/exec. It pointed at Codex session/tool runtime lifecycle and unified exec descriptor handling under retained helper pressure.Concrete repro test
I added an ignored regression test in:
Test name:
The test does this:
MCP_TEST_PID_FILE.synccall that holds the current MCP runtime.fixture.codex.shutdown_and_wait().await.Run command:
Observed failure:
Without
RUST_MIN_STACK=16777216, this same scenario can abort earlier with a Tokio worker stack overflow during shutdown, so the larger stack is useful to reach the cleaner process-retention assertion.Repro patch
Patch for the ignored repro test
Suspected root cause path
shutdown_session_runtime()currently shuts down:This repro shows that a superseded runtime can remain alive when an in-flight tool call still holds it. The latest runtime is shut down, but the old runtime held by the in-flight call is not reliably cancelled/shut down by session shutdown.
That gives a concrete source for stale stdio MCP/helper processes surviving after the owning session/thread is closed or shut down. In a long-running Desktop/app-server process, repeated occurrences can leave old helper groups and their descriptors around until app-server eventually hits the soft FD boundary and unified exec starts failing.
Useful fix invariant
Session shutdown / thread close should cancel and shut down all MCP runtime snapshots associated with that session, not only the latest published runtime. Superseded runtimes held by in-flight tool calls need an owner-session shutdown/cancellation path so their stdio children cannot survive the session that created them.
clairernovotny commentedon Jun 29, 2026
Posting the repro test source directly, since the previous comment had it inside a collapsed
<details>diff block.File:
Source to append after
refresh_keeps_superseded_mcp_server_alive_for_in_flight_calls:Run command:
Observed failure:
jamesjenkinsyates commentedon Aug 3, 2026
Adding a macOS data point that matches this closely, plus a downstream consequence I haven't seen documented: the jetsam kills corrupt unrelated user data.
Environment
26.727.51351(build 6119),codex-cli 0.146.0-alpha.9.2(process-spawning). The remaining 5 are
url =servers and cost nothing locally.Growth — single app-server, no restart
Roughly 10 GB/hour. Split at the 2h mark:
Per-server instance counts at 2h — one full stack per opened thread:
JetsamEvent reports from 27 Jul – 1 Aug show the endpoint: free memory 0.38–0.57 GB,
compressor 20.8–23.4 GB, and 1,336 distinct
nodeprocesses recorded across one boot.The part that seems under-reported
Jetsam killing processes mid-write corrupted files with no connection to Codex:
all browsing history before 31 Jul was lost permanently — Chromium marks
Historywithcom.apple.metadata:com_apple_backup_excludeItem, so Time Machine holds no copy of it.Recovery was impossible.
19:54), leaving a bundle macOS reported as "damaged and can't be opened" on every login.
codex doctorreports:rollout files are missing from the state DB; state DB rows point at missing or unusable rollout files.#21984 notes the user-visible failure mode is "not necessarily profile corruption". On this
machine it demonstrably was, and the data loss was unrecoverable.
Mitigation available today
enabled = falseper server in~/.codex/config.tomlis the only lever, and it only takeseffect on a full app restart. Either way the accumulation rate is still governed by
threads opened × stdio servers enabled, so it only changes the slope. A project-scoped
process pool as proposed in #20883 would address the root cause.
johson commentedon Aug 5, 2026
I can reproduce this on macOS with the current Codex/ChatGPT desktop app.
Immediately after restarting the app, the main desktop process started accumulating unreaped zombie children.
Observed after approximately 4m40s:
The zombie count increased at roughly 36 processes per minute. After longer use, the per-user process limit is exhausted and all local process creation begins failing with:
Quitting and restarting Codex clears the zombies temporarily, but accumulation begins again immediately after restart.
The zombies are direct children of the desktop main process, strongly indicating that exited subprocesses are not being waited on/reaped.
Visible framework version:
151.0.7922.71
macOS version:
13.3 (22E252)
Codex App version shown in “About Codex”:
26.730.61639
scyuo commentedon Aug 5, 2026
Additional sanitized reproduction on macOS:
Z/<defunct>) state during local command execution.fork failed: resource temporarily unavailable.No raw process listing, local paths, usernames, project names, task content, or logs are attached because they may contain private information.
This observation does not attribute the trigger to a specific MCP server or Computer Use feature; it is a process-reaping failure observed from normal local command execution.
galligan commentedon Aug 5, 2026
Cross-linking a measured data point for the
SkyComputerUseClientportion of this report.I posted per-client CPU measurements in #35659 for the
event-stream mcpsub-variant — the same class as the "dozens of liveSkyComputerUseClient mcpprocesses" noted here: #35659 (comment)Summary of what may be useful for triage:
0.146.0-alpha.9.2/ CU runtime26.727.1000550(newer than the builds in the linked reports).SkyComputerUseClient event-stream mcpclients against a singleSkyComputerUseService, all live children of the app-server — zeroPPID=1orphans, which separates this path from SkyComputerUseClient processes spawned for turn-ended events remain alive as PPID=1 orphans #26293 / macOS Computer Use leaks SkyComputerUseClient turn-ended helpers #29157.That last point supports the lifecycle/reaping framing in this issue rather than any single runaway process.
TralafalgarV commentedon Aug 6, 2026
Additional data point: the zombie leak has a deterministic, OS-gated trigger — and it cannot be disabled from config
I hit the same unbounded zombie accumulation described here, and was able to narrow it
down to a single code path with a deterministic trigger. Two findings below are not yet
covered in this thread and I think are directly actionable:
it was installed on, turning into an unbounded crash-retry loop.
computer-useisregistered twice (as a plugin and as an MCP server); setting
enabled = falseonboth, plus a full app restart, does not prevent the spawn loop.
Environment
kern.maxproc/kern.maxprocperuidRoot cause: minimum-OS mismatch in a bundled component
The bundled Computer Use service binary is built for a higher minimum OS than the host
it was installed on:
14.2.1 < 14.4, so the binary cannot load at all on this host. It dies beforemain(), inside dyld's Objective-C image mapping:All 15 crash reports in
~/Library/Logs/DiagnosticReports/share an identicalsignature — this is a 100% deterministic launch failure, not a race condition:
Note that this is why the crash is invisible in normal use: there is no error surfaced
in the UI, and macOS throttles crash-report writing, so
DiagnosticReportsonly retainssparse bursts rather than one report per failure.
How that becomes an unbounded zombie leak
The main ChatGPT GUI process respawns the service with no backoff and no retry cap,
and never reaps the corpses:
SkyComputerUseServicemain()— guaranteed to fail on this OSwait()/waitpid()→ every attempt leaves a<defunct>childCrash-report timestamps confirm the retry interval within each burst:
Measured leak rate — four independent 20–30 s samples, all consistent:
Cross-check against the cumulative count: 687 zombies over 19 min 35 s = 35.1/min.
At this rate the per-user process cap (2666) is reached in ~70 minutes, after which
nothing on the system can fork — every shell and application fails with
resource temporarily unavailableuntil ChatGPT is quit. Quitting the app causes launchdto reap the entire backlog immediately (867 zombies -> 24 in my case), confirming the
main process is the sole owner.
Finding 1: disabling Computer Use from config does NOT stop the spawn
This is the part I think matters most, because it will mislead anyone trying to work
around the issue. Two different binaries are involved, and the config flags only
govern one of them:
SkyComputerUseClient.../SharedSupport/SkyComputerUseClient.app/Contents/MacOS/SkyComputerUseClientSkyComputerUseService~/.codex/computer-use/Codex Computer Use.app/Contents/MacOS/SkyComputerUseServicecomputer-useis registered twice in~/.codex/config.toml:The MCP entry points at the Client. The binary that crash-loops is the Service,
spawned directly by the main GUI process.
What I verified, in order:
enabled = falseon[mcp_servers.computer-use]and[mcp_servers.node_repl].Confirmed
SkyComputerUseClientandnode_replprocesses exited.Leak rate unchanged: 470 -> 488 over 30 s (36/min).
enabled = falseon[plugins."computer-use@openai-bundled"].Leak rate unchanged (35/min) — but the app had not been restarted, so this test was
inconclusive on its own.
Leak rate still 35/min, and high-frequency sampling confirms
SkyComputerUseServiceis still being spawned ~33 times/min.So the Computer Use service spawn path ignores both the plugin flag and the MCP server
flag. There appears to be no supported way to disable it from configuration. Related:
.codex-global-state.jsoncontainscomputer-use-bundled-plugin-auto-install-disabled(default
false), andconfig.tomlcarriesSKY_CUA_SERVICE_PATH = "$HOME/.codex/computer-use/Codex Computer Use.app".Finding 2: the missing reap is specific to this path, not app-wide
Counting unique child PIDs of the main GUI process over a 20 s window (see
methodology note below) apportions the leak precisely:
SkyComputerUseService<defunct>gitps,shcodex app-server,bare-modifier-monitorSkyComputerUseServiceat ~33 launches/min accounts for essentially the entire measuredzombie rate of ~35/min. Meanwhile
git,psandshare spawned at comparable orhigher frequency by the same parent and are reaped correctly.
This narrows the defect considerably: it is not a general "the main process doesn't
reap children" problem. The Computer Use service spawn path specifically is missing its
waitpid(). That should make it much easier to locate than the broad symptom suggests.Methodology note (to avoid a false positive I initially hit)
When sampling
psin a loop, presence count is not launch count. A singlegh pr listinvocation that lives ~1.4 s appeared in 29 consecutive samples and brieflylooked like a second high-rate leak source; it was one process, and it was reaped
normally. Counting distinct PIDs instead of sample hits is what produced the
apportionment table above. Worth doing if others try to reproduce this.
Reproduction / verification commands
Suggested fixes, in priority order
LSMinimumSystemVersionbefore download andbefore launch. Shipping a
minos 14.4binary to a 14.2.1 host is the underlyingpackaging defect — it should never have been installed, let alone launched in a loop.
waitpid()to the Computer Use service spawn path. Per Finding 2 this path isthe outlier; sibling spawns in the same process are reaped correctly.
main()SIGBUS is not a transienterror; retrying every 1.7 s forever cannot succeed.
enabled = falseflags actually gate the service spawn, ordocument a supported way to disable Computer Use. Right now there is no user-accessible
mitigation short of updating the OS.
notice. The first user-visible symptom is the whole machine losing the ability to fork,
roughly 70 minutes later.
Items 1 and 3 each independently stop the bleeding on affected hosts. Item 2 is the
actual fix. Item 4 would have let users work around it without an OS upgrade.
Workaround that does work
Updating the OS to satisfy the
minos 14.4requirement (in my case macOS Sonoma 14.8.8)removes the trigger, since the binary can then load and the crash loop ends. Note this
does not fix the missing
waitpid()— it only stops it from being hit ~36 times a minute.Until then, the only reliable mitigation is to quit ChatGPT when not actively using
it; the backlog is reaped by launchd the moment the main process exits.
TralafalgarV commentedon Aug 7, 2026
Update: confirmed by controlled experiment — OS upgrade takes the leak from ~35/min to 0/min
Following up on my earlier report with verification. I upgraded the host past the
minos 14.4requirement of the bundledSkyComputerUseServicebinary. No configurationwas changed between the two states — only the OS version.
minos 14.4satisfied?SkyComputerUseServicemain()The last crash report is timestamped
2026-08-07 11:55:15, immediately before theupgrade; none have been produced since (~1 h 40 m of uptime at the time of writing).
This closes the causal chain. The binary was simply unable to load on a host below its
minos, and what produced the leak was the unbounded, no-backoff retry of a spawn thatwas guaranteed to fail, combined with the missing reap. Once the binary can load, the
same spawn path — with the same configuration — behaves correctly and leaks nothing.
Two things I want to stress, because the upgrade is a workaround and not a fix:
waitpid()on this path is still there. The upgrade only stops it frombeing hit ~36 times a minute. Any future spawn failure on that path will resume leaking
at the same rate.
enabled = falseon both[plugins."computer-use@openai-bundled"]and[mcp_servers.computer-use], followed bya full app restart, did not prevent the spawn loop — verified at ~33 spawns/min while
both were disabled. Users below the required
minoswho cannot upgrade have no optionother than quitting the app periodically.
So I would still suggest gating the component on
LSMinimumSystemVersionbefore downloadand before launch, adding backoff plus a retry cap, and adding the missing reap. Happy to
provide raw crash reports or additional sampling data if useful.
s0601737-boop commentedon Aug 9, 2026
Additional reproduction on ChatGPT/Codex Desktop for macOS.
Environment:
Isolation test:
This makes the tracker plugin an unlikely root cause. Restarting Desktop clears the accumulated zombies temporarily, but the issue can recur during a long-running session.
Please investigate Desktop child-process lifecycle/reaping for app-server and MCP helpers, including cleanup after a thread/tool ends or fails. No source code, prompts, or private files are attached.
scyuo commentedon Aug 10, 2026
Follow-up: Sonoma 14.8.9 is sufficient; still at 0 zombies after 23+ hours
A lower-risk workaround than moving to Tahoe is now confirmed on the affected host.
I upgraded the OS from macOS 14.2.1 to macOS Sonoma 14.8.9 (23J631), while keeping the ChatGPT/Codex Desktop configuration unchanged. The bundled
SkyComputerUseServicestill declaresminos 14.4, so 14.8.9 satisfies its loader requirement.Post-upgrade results:
26.803.41515SkyComputerUseService: one stable, long-lived process00 -> 0 -> 0 -> 00 -> 0 -> 0across another 30-second sampleSkyComputerUseServicecrash reports were produced after the upgradeBefore the upgrade, the host was below the binary's minimum OS version and the service failed before
main()roughly every 1.7 seconds, leaking about 35 zombies per minute. After upgrading to Sonoma 14.8.9, the measured leak rate remains 0/min.For users affected specifically by this
minos 14.4mismatch, upgrading the OS is an effective temporary workaround. Sonoma 14.8.9 is directly confirmed; upgrading all the way to Tahoe is not required. Other macOS releases at or above 14.4 should satisfy the binary's declared minimum version, although they were not all individually tested.This remains a workaround, not the underlying fix: the spawn path should still gate on the binary's minimum OS version, add retry backoff/capping, and reap failed children correctly.
asheppard47 commentedon Aug 17, 2026
Observed
node_repldirect children totaling 157.2 MiB, oldest 12 hours 19 minutes; 3 stdio app-server helpers totaling 52.8 MiB; 1SkyComputerUseprocess totaling 14.3 MiB; zero zombies.code_sign_clonedirectories were present.Inference
This reproduces on an OS above the reported
minos 14.4threshold, so it is not the loader-crash subtype described in later comments.Could maintainers provide a supported cleanup command or lifecycle fix? A global
pkillis unsafe because long-running tasks may still own workers.jonmc12 commentedon Aug 19, 2026
Corroborating reproduction on a current macOS desktop build
I reproduced the same stale-helper accumulation and recovered the affected Codex task with scoped cleanup.
Environment
26.814.41407(bundle6720)Observed
108SkyComputerUseClientprocesses129node_replprocesses3.6 GB RSSand55% CPUstream disconnected before completion: error sending request for url (https://chatgpt.com/backend-api/codex/responses)Scoped cleanup experiment
I selected only helper processes older than one hour that predated the current app session, preserving the GUI, primary app-server, and current-session helpers. I sent
SIGTERMonly—no task/session files were removed.217114node_repl103SkyComputerUseClient3.2 GB RSSand60.2% CPU24413 MB RSSand3.4% CPU0After cleanup, the original affected task successfully completed a bounded readiness request and returned to idle. A long, tool-heavy run has not yet been used to prove complete resolution, so I am treating this as strong lifecycle/resource evidence rather than proof that every stream disconnect shares this cause.
This appears to support session/tool-scoped lifecycle cleanup, retry/backoff, and child reaping rather than relying on global process termination.
yulonglin commentedon Aug 25, 2026
Still reproducible on 26.818.31338.
SkyComputerUseServicerespawned within minutes even aftercodex plugin remove computer-history@openai-bundled, deleting thenotifyturn-ended hook from~/.codex/config.toml, and removing~/.codex/computer-use— the app re-adds the hook and relaunches from the copy bundled inside ChatGPT.app. Note the AX polling charges its cost to the victim apps' main threads, so the service looks idle in Activity Monitor while causing system-wide typing lag;sample <victim app>during a stutter shows it. Only reliable mitigation we've found: a launchd agent that pkillsSkyComputerUse|CUALockScreenGuardianevery 30s.diegocantarero commentedon Sep 12, 2026
Current reproduction on Codex Desktop 26.903.71938 (build 8576), sanitized: one main Desktop process and one SkyComputerUseService are running, but the same live session accumulated 57 SkyComputerUseClient processes and 38 node_repl processes. The clients were spawned in repeated timestamp clusters over roughly 24 minutes and remain parented by the active Codex process; they are not duplicate GUI instances. Aggregate sampled RSS was about 1.68 GiB for SkyComputerUseClient and 0.49 GiB for node_repl. I did not terminate them because multiple active tasks may own live tool sessions. During the same observation, read-only Computer Use acquisition succeeded for Activity Monitor, Finder, and Chrome, while earlier runs had intermittent -10005/noWindowsAvailable. This strengthens the lifecycle/leak hypothesis and suggests the app needs per-session ownership plus safe teardown/reaping after each MCP/Computer Use session ends. No raw logs, task IDs, account data, or private paths are included.
yulonglin commentedon Sep 12, 2026
This has been so bad I've switched off computer use, disabled all computer use permissions and set up jobs to reap SkyComputerUse processes ever 30s, as mentioned above.
giorgio-zamparelli commentedon Sep 30, 2026
Adding a measured macOS case where one long-lived Computer Use helper with an active capture stream was enough to cause noticeable typing lag and skipped cursor frames. This did not require a large collection of live helpers.
Environment:
com.openai.codex; it displays the name ChatGPT on this installation. The version currently on disk is 26.924.22138 (11645). The app had been running since before the investigation, so that is not a verified running-app version.SkyComputerUseServicebundle wascom.openai.sky.CUAService, version 26.923.1001242 (1001242), located in the Codex Computer Use helper bundle. It had been alive for about 30 hours.The helper's native sample showed
com.openai.sky.CUAService.CaptureStreamcallbacks, CMCapture sample-buffer processing, and IOSurface work. The separate Orca Computer Use helper was idle. I have not established whether the OpenAI stream was started by Computer Use, Computer History, or foreground-app context. Those features share this helper, so process lifetime alone is not proof of an abandoned session.Controlled local comparison, with the desktop app and Orca left running:
The helper itself had been using about 16-19% of one CPU core. Ending that specific helper with SIGTERM released the capture stream. CPU die temperature subsequently fell from about 75 C to 51-53 C, GPU temperature from about 69 C to 49-51 C, fans from roughly 5,357 to 2,502 RPM, and thermal state from Fair to Nominal. These temperatures/fan readings are follow-up observations rather than identical-duration averages. The user immediately confirmed that input and cursor movement were substantially more responsive.
Temporarily suspending and resuming the helper had produced a much smaller WindowServer change (about 92% to 81%), so pausing a process while retaining capture resources did not reproduce the benefit of fully releasing the stream. Pausing the performance monitor did not materially reduce WindowServer load.
This is evidence that the active capture pipeline was a major contributor on this setup; it does not identify the exact native-service bug or establish that all WindowServer/input stalls have this cause. The high-resolution display configuration may amplify the cost.
Useful fixes or diagnostics to investigate:
I am also preparing a Mac Performance Monitor diagnostic for this combination of display-service and capture-helper activity. That can point users toward the capture owner, but the underlying stream lifecycle/performance fix belongs here.
Only summarized measurements are included here; no raw process inventory, screen images, or user activity history is attached.