[app][macOS][26.810.52044] Unbounded SkyComputerUseService respawn loop crashes the app in ~2 min — onServiceConnectionLost has no failure counter, backoff, or circuit breaker
[app][macOS][26.810.52044] Unbounded SkyComputerUseService respawn loop crashes the app in ~2 min — onServiceConnectionLost has no failure counter, backoff, or circuit breaker
Summary
On macOS, the ChatGPT/Codex desktop app enters an unbounded respawn loop for the Computer Use PiP helper (SkyComputerUseService) whenever the PiP bootstrap handshake fails. Each iteration leaks a live 75 MB helper process and permanently blocks a main-app thread, so the app reaches the V8 heap limit and aborts roughly 2 minutes after launch — with no user interaction and without Computer Use ever being invoked.
The native (ObjC/C++) side of the handshake is implemented correctly: it has a 15 s Apple Event timeout, a 5-attempt cap, and exponential backoff. The defect is in the JavaScript layer above it, where the connection-lost callback is a no-op that only nulls the cached PID. I have traced this to a specific callback in app.asar and include a proposed patch below.
This appears to be the same underlying defect behind several existing reports (see [Related](#related-issues)); this issue adds the root cause and a specific code location.
---
Environment
| | |
|---|---|
| App | ChatGPT.app 26.810.52044 (build 6662), bundle id com.openai.codex |
| Framework | Codex Framework 151.0.7922.137 |
| macOS | 26.3 (25D125) |
| Hardware | Mac16,10 (Mac mini, Apple Silicon), 16 GB RAM |
| Computer Use helper | 26.812.1000717, at ~/.codex/computer-use/Codex Computer Use.app |
| Install source | https://persistent.oaistatic.com/codex-app-prod/ChatGPT.dmg (verified: the downloaded DMG is byte-identical in version/build to the installed app) |
Reported crashing builds in the community thread: 6570, 6644, 6662.
---
Reproduction
- Launch ChatGPT.app.
- Do nothing. Do not open a project, do not use Computer Use, do not interact at all.
- The app aborts after ~70–150 s.
100% reproducible on this machine across 5+ consecutive launches.
---
Observed behaviour
Helper process explosion
SkyComputerUseService instances, all children of the main app process, none reaped:
| Time since launch | Live helper processes | Combined RSS |
|---|---|---|
| 12 s | 36 | ~2.7 GB |
| 25 s | 79 | ~5.9 GB |
| 30 s | 105 | ~7.9 GB |
| ~40 s (manually killed) | 199 | 12.5 GB |
Spawn rate ≈ 5/s. Each helper is ~75 MB and stays alive and healthy — sampling one shows a normal, idle NSApplicationMain run loop parked in mach_msg2_trap. They are never asked to exit and never reaped.
Main-process thread exhaustion
| Time since launch | Threads in main process |
|---|---|
| 5 s | 2 |
| 60 s | 209 |
| 120 s | 309 → crash |
Growth is linear and monotonic; threads are never released.
Crash report
Exception Type: EXC_CRASH (SIGABRT)
Termination Reason: Namespace SIGNAL, Code 6, Abort trap: 6
Dispatch Thread Soft Limit Reached: 64 (too many dispatch threads blocked in synchronous operations)
Triggered by Thread: 9 V8Worker
Thread 9 Crashed:
0 libsystem_kernel.dylib __pthread_kill
1 libsystem_pthread.dylib pthread_kill
2 libsystem_c.dylib abort
3 Codex Framework node::OOMErrorHandler(char const*, v8::OOMDetails const&)
Thread-name histogram at crash time (321 threads total):
187 computer-use
64 com.apple.root.user-initiated-qos
16 ThreadPoolForegroundWorker
...
Every one of the 187 computer-use threads is parked identically:
libsystem_kernel.dylib __ulock_wait
libdispatch.dylib _dlock_wait
libdispatch.dylib _dispatch_group_wait_slow
AE AESendMessage
node.napi.armv8.node ffi_call_SYSV
sky.node Napi::details::CallbackData<...>::Wrapper
Codex Framework napi_is_detached_arraybuffer
and the 64 QoS threads (which is exactly the dispatch soft limit) are parked in:
AE AESendMessage
Foundation -[NSAppleEventDescriptor sendEventWithOptions:timeout:error:]
sky.node -[RemoteHostedPIPContentService sendBootstrapToServiceWithProcessIdentifier:rendezvousPort:attempt:]
Log evidence
log stream --predicate 'process == "ChatGPT"' during startup:
sky.node RemoteHostedPIPContent started private endpoint host
xpc [0x...] failed to do a bootstrap look-up: xpc_error=[3: No such process]
appleevents AESendMessage(SkCu,PiPB {SkCu,PiPB target='kpid'[pid=32651 returnID=24465}...
appleevents AESendMessage(SkCu,PiPB {SkCu,PiPB target='kpid'[pid=32700 returnID=-4047}...
appleevents AESendMessage(SkCu,PiPB {SkCu,PiPB target='kpid'[pid=32705 returnID=22616}...
appleevents AESendMessage(SkCu,PiPB {SkCu,PiPB target='kpid'[pid=32709 returnID=...}...
The target PID differs on every send — confirming a fresh helper is spawned per attempt rather than the existing one being reused.
---
Root cause
The native retry logic is correct
Disassembly of -[RemoteHostedPIPContentService sendBootstrapToServiceWithProcessIdentifier:rendezvousPort:attempt:] in Contents/Resources/native/sky.node (symbols are not stripped; function at 0xd474):
Event construction — eventClass = 'SkCu', eventID = 'PiPB':
d504 mov w2, #0x4375
d508 movk w2, #0x536b, lsl #16 ; 'SkCu'
d50c mov w3, #0x5042
d510 movk w3, #0x5069, lsl #16 ; 'PiPB'
d520 bl appleEventWithEventClass:eventID:targetDescriptor:returnID:transactionID:
Send with a bounded 15 s timeout (options = 0x23 = kAEWaitReply | kAECanInteract):
d5d4 fmov d0, #15.00000000 ; timeout = 15 s
d5e0 mov w2, #0x23 ; kAEWaitReply | kAECanInteract
d5e4 bl sendEventWithOptions:timeout:error:
Attempt cap of 5 (attempt arrives in x4, spilled to [sp,#0x10]):
d494 str x4, [sp, #0x10] ; save attempt
...
d73c ldr x10, [sp, #0x10]
d740 sub x8, x10, #0x5
d744 cmn x8, #0x7
d748 b.hi 0xd7b4 ; attempt in 0..4 -> retry; attempt >= 5 -> give up
Exponential backoff, 50 ms << attempt (0xF4240 = 1e6 ns/ms):
d7b4 mov w8, #0x32 ; 50
d7b8 lsl x8, x8, x10 ; 50 << attempt
d7bc mov w9, #0x4240
d7c0 movk w9, #0xf, lsl #16 ; 1_000_000
d7c4 mul x1, x8, x9 ; -> nanoseconds
d7d0 bl dispatch_time
d7e0 bl dispatch_get_global_queue
So the native layer retries at 50/100/200/400/800 ms (5 attempts, ~1.55 s total) and then correctly gives up, logging and dispatching the failure callback to the main queue.
The JavaScript layer discards that failure
From Contents/Resources/app.asar (minified; identifiers are the shipped mangled names):
te = () => {
if (!(D || v || !n || !t()) && (
oe(),
v = ko({
controlTooltips: c(),
onServiceConnectionLost: () => { b = null } // <-- the entire failure handler
}),
v
)) {
b != null && Ao(b), se(), B(), ce(), le(), me()
for (let e of _) e()
}
}
where ko(...) → startRemoteHostedPIPContentHost(tooltips, onServiceConnectionLost), Ao(pid) → connectRemoteHostedPIPContentHost(pid), and the spawn path is:
async function Eo(path, { addon: t, electronAppPath: n, platform: r, resourcesPath: i } = {}) {
return r !== `darwin` || path.trim() === ``
? null
: (t ?? so({ electronAppPath: n, resourcesPath: i })).spawnComputerUseService(path)
}
onServiceConnectionLost only nulls the cached PID. There is no failure counter, no delay, no ceiling, and no disable path. Once b is null, the next invocation of te() — triggered by ordinary UI/state changes — spawns another helper immediately, and the previously spawned helper is never terminated.
Searching the entire 267 MB app.asar for any restart-throttling mechanism:
| identifier | occurrences |
|---|---|
| maxRestart | 0 |
| restartCount | 0 |
| consecutiveFailure | 0 |
| circuitBreak | 0 |
No global restart circuit breaker exists.
Why the handshake fails in the first place
Not fully determined. The XPC bootstrap look-up fails with [3: No such process] immediately before the app falls back to the Apple Event path, and the spawned helper — while alive and idle in a normal run loop — never answers SkCu/PiPB.
Note that com.openai.codex has Apple Events authorization entries for com.apple.Terminal, com.apple.finder, com.apple.systemevents, com.google.Chrome and others, but no entry targeting com.openai.sky.CUAService, while other clients on this machine (python, node, other apps) do have that pairing. tccd logs during startup show no AppleEvents authorization request for that target, so this is an observation rather than a confirmed cause.
Regardless of why the handshake fails, the unbounded respawn is an independent defect and is what turns a recoverable failure into a crash.
---
Proposed fix
Give onServiceConnectionLost a failure counter, backoff, and circuit breaker, and reap the previous helper before spawning a new one:
let cuFailCount = 0
let cuDisabled = false
onServiceConnectionLost: () => {
b = null
if (cuDisabled) return
if (++cuFailCount >= 3) {
cuDisabled = true // stop trying; surface a UI notice
log.warn('Computer Use host unavailable; disabling for this session')
return
}
setTimeout(te, Math.min(1000 * 2 ** cuFailCount, 30_000))
}
and reset cuFailCount = 0 on a successful connect.
Additionally:
- Terminate the previous helper before spawning a replacement.
spawnComputerUseServiceshould either reuse a live helper (computerUseServiceProcessMatchesExecutablePathalready exists for this check) or kill the stale one. Today, helpers accumulate without bound and are never reaped — this is also the substance of #25744 and the zombie-process reports. - Bound in-flight bootstraps. With a 15 s Apple Event timeout and a ~200 ms spawn cadence, up to ~75 bootstraps can be in flight simultaneously, each holding a blocked thread. The 64-thread dispatch soft limit is hit well before any of them time out.
- Do not run the bootstrap on
com.apple.root.user-initiated-qos. Synchronously blocking global-queue threads onAESendMessageis what exhausts the dispatch pool.
---
Workaround (verified)
Making the helper bundle non-executable stops the loop entirely:
chmod 000 "$HOME/.codex/computer-use/Codex Computer Use.app"
Result — measured over a continuous 14.5 h run:
| | before | after |
|---|---|---|
| Helper processes | 199 and climbing | 0 |
| Main-process threads | 309 @ 2 min | 63, flat |
| App memory | 12.5 GB and climbing | 347 MB, flat |
| Stability | crash @ ~2 min | no crash in 14.5 h |
Computer Use is unavailable, but every other feature works normally. Reverse with chmod 755 on the same path.
Deleting or renaming the helper bundle does not work — the app re-provisions an identical copy on next launch.
---
Possibly related: idle renderer memory growth
Likely a separate defect, noted here because it appears in the same reports. On a clean launch with nothing opened, the app starts 7 renderers. Four of them (renderer-client-id 7–10, created within 36 ms of each other and identical in size) grow steadily while completely idle:
| renderer | at launch | after 14.5 h | growth |
|---|---|---|---|
| #5 (main UI) | 304 MB | 346 MB | +14% |
| #6 | 182 MB | 263 MB | +45% |
| #7 | 102 MB | 1428 MB | +1300% |
| #8 | 101 MB | 1426 MB | +1300% |
| #9 | 102 MB | 1425 MB | +1300% |
| #10 | 100 MB | 1424 MB | +1300% |
Measured rate ≈ 320 MB/h per renderer (16 MB per 3 min, sampled). Growth is in app-specific tag 14 (JS heap): 1145 MB → 1373 MB, with region count rising 4385 → 4754.
Notably these four processes accumulated only 2.5–9.3 seconds of CPU time over 14.5 hours, so whatever is allocating is doing almost no work. Total app footprint reached 7.67 GB; a restart brings it back to 1.45 GB. On a 16 GB machine this drove swap to 7.74 GB of 8 GB.
The renderers that are actually in use are fine — the leak is in the four idle pre-warmed ones.
---
Related issues
- ChatGPT Desktop 26.810.50856 crashes after 1–3 minutes — computer-use / sky.node thread exhaustion — same crash; independently observed the same 187-thread signature
- Codex desktop app on macOS continuously creates zombie SkyComputerUseService processes
- #25744 — Computer Use / MCP helper process accumulation, unreaped children
- #33582 —
[app][macOS]grows to 55 GB and freezes the system - #36920 —
[app][macOS]3–5 GB RAM with no project open
---
Contact
Happy to provide the full .ips crash reports, log stream captures, disassembly, or to run any additional diagnostics on request — just ask here.
---
Notes on this machine's configuration
For completeness: this machine uses a customized ~/.codex/config.toml (custom openai_base_url pointing at a local router, custom model catalog, sandbox_mode = "danger-full-access", 6 MCP servers), and ~/.codex is a symlink to an external volume. The failure path above is entirely within the Computer Use PiP bootstrap and is independent of model routing; the identical crash signature has been reported by users on stock configurations.
4 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
this actually crashes my mac not just chatgpt. no other app open, one prompt, 2min later mac freezes then screen goes black. only holding power button resolves it, no input is registered. I downgraded to 26.803.61601 that fixes it. writeup https://spreen.co/codex-macos-crash-transcript/
Follow-up: still reproducible on builds 6849 and 6962, with 16 crash reports
I have a longitudinal evidence set for the same unbounded Computer Use respawn/thread-exhaustion failure described here. The important new information is that the issue continued after build 6662 in two later app builds and two later Computer Use runtimes.
Environment and affected versions
Mac17,3), 10 logical CPUs, 16 GB RAM25E253)com.openai.codex26.810.52044(build6662) / Computer Use26.812.100071726.818.21641(build6849) / Computer Use26.818.100079026.818.41509(build6962) / Computer Use26.819.1000816Crash-report evidence
There are 16 original macOS
.ipsreports from Aug 15-23, 2026:666268496962computer-useorV8Worker(9computer-use, 7V8Worker).EXC_CRASH / SIGABRT; their faulting stacks containnode::OOMErrorHandler(...) -> abort().EXC_BREAKPOINT / SIGTRAP, also on acomputer-useworker path.Dispatch Thread Soft Limit: 64.computer-useand exactly 64com.apple.root.user-initiated-qosthreads. The latter are blocked inAESendMessage -> -[NSAppleEventDescriptor sendEventWithOptions:timeout:error:] -> -[RemoteHostedPIPContentService sendBootstrapToServiceWithProcessIdentifier:rendezvousPort:attempt:].The two build
6962crashes occurred 2m03s and 1m54s after launch. This is the same timing and crash shape as build6662, not a separate generic Electron OOM.Process and system impact observed
SkyComputerUseServicecount reached 458 on build6662and 547 on build6849.6662and 450.49 on build6849on a 10-logical-CPU system.PreventUserIdleSystemSleepassertions, so the incident also prevented normal sleep and caused severe battery/thermal impact.Reproduction and mitigation observations
6234with Computer Use26.803.1000621remained stable, while later runtimes1000717,1000790, and1000816reproduced the issue.Interpretation
The crash reports directly confirm main-process Computer Use worker accumulation, dispatch-pool exhaustion, and V8 OOM/abort. The live process samples independently confirm an unbounded
SkyComputerUseServicepopulation owned by ChatGPT. Together these observations support the root cause described in this issue: a failed bootstrap is converted into an unbounded respawn loop without a global in-flight limit, backoff/circuit breaker at the caller, or cleanup of prior helpers.The initial reason the bootstrap handshake fails on this machine is still not established. That should remain separate from the confirmed containment defect: one failed handshake must not be able to create hundreds of processes/threads, prevent sleep, overload the machine, and crash the app.
Requested follow-up
6962/ Computer Use1000816.I can provide the 16 original
.ipsreports privately. I am not attaching them publicly because they contain local device and diagnostic identifiers.I also have this issue. After 2 minutes the app crashes.