[macOS] 26.810.41047: main-process spawnSync storm respawns the plugin app-server ~5×/sec, freezing the UI and system input

Resolved 💬 2 comments Opened Aug 14, 2026 by Tygb99 Closed Aug 14, 2026
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What version of the Codex App are you using (From “About Codex” dialog)?

26.810.41047 (build 6570), macOS

What subscription do you have?

ChatGPT Plus

What platform is your computer?

Darwin 25.5.0 arm64 arm — macOS 26.5.2 (25F84), Apple M4, 10 cores, 24 GB RAM

What issue are you seeing?

After the app auto-updated to 26.810.41047 on 2026-08-14 at 17:04 KST, the app becomes unusable within seconds of launch: the UI freezes, system-wide input lags, and CPU saturates.

The cause is a spawnSync storm in the Electron main process: the app repeatedly spawns Contents/Resources/codex (a 219 MB binary) synchronously, blocking the main thread.

1. Child-process churn (measured)

Sampling every ChatGPT-family process every 2 s for a 14-second window right after launch:

| t after launch | live Resources/codex children |
|---|---|
| +14 s | 19 |
| +16 s | 27 |
| +18 s | 21 |
| +20 s | 13 |
| +22 s | 2 |
| +24 s | 11 |
| +26 s | 16 |
| +28 s | 20 |

The PIDs are completely different at each snapshot — these are not long-lived workers:

  • 75 unique Resources/codex PIDs observed in that 14-second window
  • PID space advanced from 80731 to 81455 (724 PIDs consumed)
  • 5 spawns per second, sustained
  • Each child holds 40–120 MB RSS; the main process footprint peaked at 597 MB
2. Stack evidence: the spawns are synchronous

sample of the main process (pid 80696, 12 s, 8814 samples/thread) resolves the spawn path to Node's synchronous runner:

node::SyncProcessRunner::Spawn(v8::FunctionCallbackInfo<v8::Value> const&)  (in Codex Framework) + 640
uv_spawn  (in Codex Framework) + 2732
posix_spawn  (in libsystem_kernel.dylib) + 496
__posix_spawn  (in libsystem_kernel.dylib) + 0

SyncProcessRunner is child_process.spawnSync. Calling it ~5×/s on the Electron main thread blocks the event loop, which is why the whole UI — and, through it, my remote input — stops responding.

Supporting hotspots in the same sample: heavy v8::ArrayBuffer::New churn and node::IsolateData::CreateIsolateData / node::worker::MessagePort::New, consistent with each spawn tearing down and rebuilding worker state.

3. Log fingerprint: IPC router re-election storm

Each spawned client re-registers over IPC and re-runs router election. Comparing the last pre-update session against the post-update sessions in ~/Library/Logs/com.openai.codex/:

| session | app version | uptime | [IpcRouter] I am the router | log files written |
|---|---|---|---|---|
| pid 93935 | pre-update | 10 h 56 min | 0 | 2 |
| pid 83373 | 26.810.41047 | 2 min | 158 | 65 |
| pid 89094 | 26.810.41047 | 2 min | 171 | 73 |
| pid 58173 | 26.810.41047 | 4 min 30 s | 296 | 127 |

The three short sessions are short only because I force-quit them. [IpcRouter] I am the router does not appear even once in the 2,320-line pre-update log covering nearly 11 hours; it appears 158–296 times per 2–4 minutes afterwards.

The app also opens a new log file per spawn (…-t0-… through …-t126-…). Pre-update sessions wrote exactly 2 log files. Post-update sessions wrote 65–127, nearly all zero-byte.

Broadcast storms accompany this — up to 45 log lines in a single second, dominated by:

warning [IpcClient] Received broadcast but no handler is configured method=client-status-changed

Sessions end with the router's socket breaking:

warning [IpcRouter] Socket error errorCode=EPIPE errorMessage="write EPIPE"
    at Tse.broadcastClientStatus (…/app.asar/.vite/build/src-BlUt09P1.js:1032:7497)
    at Tse.unregisterClient (…/app.asar/.vite/build/src-BlUt09P1.js:1032:6594)
4. Possible trigger (hypothesis, not proven)

The bundled plugin app-server was not refreshed by the update. The installed copy is still the one written by the previous version:

| file | size | sha256 (first 16) | mtime |
|---|---|---|---|
| /Applications/ChatGPT.app/Contents/Resources/codex | 219,666,000 | 7a26b07855ef9119 | 2026-08-14 17:04 |
| ~/.codex/plugins/.plugin-appserver/codex | 218,437,552 | 04ddea2f332bd524 | 2026-08-11 17:58 |
| /Applications/ChatGPT.app/Contents/Resources/codex-code-mode-host | 51,495,456 | 206000a48fbe9d2f | 2026-08-14 17:04 |
| ~/.codex/plugins/.plugin-appserver/codex-code-mode-host | 49,992,576 | 75575bbeae891d4e | 2026-08-11 17:58 |

Both installed copies are stale and hash-mismatched against the bundle, so the file-equivalence check in chrome-plugin-app-server-runtime (the XK sha256 helper identified in #38547) can never succeed. A reconcile that re-checks and re-launches on every failure would produce exactly this unbounded respawn loop.

I want to be explicit that this part is a hypothesis: on macOS bundled_plugins_reconcile_started only appears 2–3 times per session in the logs, so I have not proven the reconcile path is the caller of the spawnSync loop. The measured facts are the spawn rate, the synchronous stack, and the router storm.

What steps can reproduce the bug?

  1. On macOS 26.5.2 (Apple Silicon), let the Codex app auto-update to 26.810.41047 from a 26.803.x build.
  2. Launch the app. Do not open a conversation, the in-app Browser, or start any task.
  3. Within ~10 s, run ps -Ao pid,pcpu,comm | grep 'ChatGPT.app/Contents/Resources/codex' repeatedly and observe the PIDs turning over completely every couple of seconds.
  4. Observe the UI stop responding and system-wide input latency.
  5. Quit the app — responsiveness returns immediately.

Reproduced on 3 of 3 launches since the update (19:57, 20:01, 22:44 KST) plus a 4th deliberate reproduction at 23:03 KST for this report. Zero occurrences in the ~11 h pre-update session on the same machine, same day.

What is the expected behavior?

The app should launch and sit idle without repeatedly spawning the plugin app-server, and any app-server launch or file-equivalence check should be asynchronous so it can never block the Electron main thread. A failing equivalence check should back off and surface an error rather than retry unbounded.

Additional information

  • Related, same 26.810 train, but different platform and different mechanism: #38551 and #38547 (Windows). #38547 identifies the sha256 equivalence check in chrome-plugin-app-server-runtime as the Windows hot path; on macOS the observable failure is a spawnSync process storm, and the UI freeze is far more severe.
  • Not a duplicate of #27497 (that one hangs before window creation, tied to auth.json); here the window opens and then the spawn loop starts.
  • The sample output (10.7 MB) and the raw ps churn log are available on request.
  • Only the codex app-server children churn; the Chromium renderer and GPU helpers stay in normal ranges apart from brief spikes.

View original on GitHub ↗

2 Comments

github-actions[bot] contributor · 13 days ago

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

  • #38455
  • #37311

Powered by Codex Action

Tygb99 · 13 days ago

Closing as a duplicate of #38455 — same build (26.810.41047, 6570) and the same child-process respawn loop, seen from the freeze side rather than the OOM-crash side. Related: #37311 (same Resources/codex app-server respawn on an earlier build, surfacing as zombies).

I have moved the evidence that was unique to this report into #38455: https://github.com/openai/codex/issues/38455#issuecomment-5294882675 — specifically the node::SyncProcessRunner::Spawn -> uv_spawn -> posix_spawn stack showing the spawns are synchronous on the Electron main thread (which explains the system-wide input freeze), the measured churn of 75 unique child PIDs in 14 seconds, and the before/after log comparison across the update.

Please track it there.