[macOS] 1,360 Node processes consume 41 GB and hang WindowServer within 20 minutes of restart
Summary
A Codex Desktop MCP/Node lifecycle failure escalated into two system-wide outages on a 16 GB Apple Silicon Mac.
This appears related to #30408, but adds a materially more severe failure mode on the current desktop build: after the first memory-exhaustion restart, the process fleet grew again to 1,360 system-wide Node processes with a 41.32 GiB aggregate footprint in under 20 minutes. WindowServer then failed its userspace watchdog and the computer restarted again.
Environment
- Desktop bundle: ChatGPT/Codex 26.707.31123
- Bundle build: 5042
- Bundled app-server: codex-cli 0.144.0-alpha.4
- macOS 26.5.1 (25F80)
- Mac mini, Apple M4
- Physical memory: 16 GB
First failure: macOS Jetsam evidence
macOS generated two JetsamEvent reports 5 minutes 56 seconds apart. Both reports use a 16,384-byte page size.
| Snapshot | All Node processes | Node in Codex coalition | All-Node resident footprint | Codex coalition processes | Codex coalition resident footprint | Free memory |
|---|---:|---:|---:|---:|---:|---:|
| 06:20:05 | 760 | 755 | 1,662,363 pages = 25.37 GiB | 799 | 1,895,040 pages = 28.92 GiB | 5,445 pages = 85.1 MiB |
| 06:26:01 | 843 | 842 | 1,778,409 pages = 27.14 GiB | 881 | 2,034,698 pages = 31.05 GiB | 2,246 pages = 35.1 MiB |
In 5 minutes 56 seconds:
- Node count increased by 83.
- Codex-coalition process count increased by 82.
- All-Node resident footprint increased by 1.77 GiB.
- Codex-coalition resident footprint increased by 2.13 GiB.
A separate Node diagnostic report recorded this ownership chain:
~~~text
responsibleProc = ChatGPT
coalitionName = com.openai.codex
parentProc = node
~~~
At 06:26 the system compressor occupied 9.40 GiB and represented 50.99 GiB of uncompressed system-wide pages. That compressor value is system-wide and is not attributed entirely to Codex.
The machine was manually restarted at 06:32:18 after becoming unusable.
Second failure after restart
A userspace-watchdog spin report captured the system at 06:51:54, approximately 19 minutes 36 seconds after the first restart:
| Process family | Count | Aggregate footprint |
|---|---:|---:|
| Node | 1,360 | 42,312.49 MiB = 41.32 GiB |
| Codex Renderer | 4 | 945.68 MiB |
| codex | 2 | 546.63 MiB |
| ChatGPT | 1 | 340.66 MiB |
| Codex Service | 3 | 186.44 MiB |
| node_repl | 11 | 65.05 MiB |
| WindowServer | 1 | 998.67 MiB |
The watchdog report does not contain coalition IDs for each of the 1,360 Node processes, so this report alone cannot prove that every one belonged to Codex. However:
- the immediately preceding Jetsam reports attributed 842 of 843 Node processes to the Codex coalition;
- live process inspection showed repeated app-server-owned batches of Playwright MCP, Chrome DevTools MCP, XcodeBuildMCP, plugin server.mjs processes, and node_repl;
- earlier batches remained alive while later batches appeared.
At 06:52:05 macOS recorded:
~~~text
monitoring timed out for service
unresponsive work processor(s): WindowServer main thread
42 seconds since last successful checkin
~~~
WindowServer was not spinning on CPU: its main thread used about 0.105 seconds of CPU across 11 samples. The sampled stacks were blocked in SkyLight / QuartzCore / kernel paths, with some samples passing through APFS compressed-file reads. This supports a blocked system graphics session, but the unsymbolicated stack is not enough to claim a GPU-driver root cause.
The system restarted again at 06:55:24.
Reproduction observations
During tool-enabled Codex activity, repeated process batches included:
~~~text
npm exec @playwright/mcp@latest
npm exec chrome-devtools-mcp@latest
npm exec xcodebuildmcp@latest mcp
node ./scripts/start-mcp.mjs
node ./mcp/server.mjs
cua_node/bin/node_repl
~~~
The interval included both an initial multi-agent diagnostic phase and later serial tool calls. Therefore the evidence does not isolate concurrency as the sole trigger or prove the exact spawn boundary. It does show that the process fleet remained unbounded across normal tool-host activity.
Expected behavior
MCP and tool-host subprocesses should be reused or torn down at a bounded lifecycle boundary. Their count and memory footprint must remain bounded regardless of thread, subagent, or tool-call volume.
Actual behavior and impact
The Node/MCP process fleet accumulated until macOS had only about 35 MiB of free pages, then reproduced after restart and reached 41.32 GiB of system-wide Node footprint. WindowServer stopped responding and the machine restarted.
This is not merely elevated application RAM. It is a system-availability failure.
Evidence boundaries and privacy
Verified facts above come from macOS JetsamEvent reports, a Node diagnostic report, a WindowServer watchdog report, and a live process-tree snapshot.
Not yet proven:
- whether each process batch is keyed to a thread, subagent, tool-host instance, or individual tool call;
- whether every Node process in the second watchdog snapshot belonged to Codex;
- whether WindowServer was blocked by memory pressure, I/O pressure, or another downstream mechanism.
Project names, usernames, local paths, prompts, and raw session logs are intentionally omitted. Sanitized report excerpts and aggregation commands can be provided privately.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗