ChatGPT Desktop for macOS: deterministic main-process V8 heap OOM at startup (builds 6644 and 6662)
Summary. The ChatGPT desktop app (com.openai.codex) dies 7 to 17 seconds after every launch. The
crash reporter shows EXC_BREAKPOINT (SIGTRAP) on CrBrowserMain, but the underlying failure is a
JavaScript heap out-of-memory in the Electron main process. The heap climbs from zero to the
~3.9 GB ceiling in under 7 seconds and V8 aborts. The allocation runaway is silent: fewer than 100 log
lines are emitted before death and none of them repeat.
This is not the computer-use thread-exhaustion leak reported for this same build train. Thread
count is flat across every crash. See "Distinguishing this from the known report" below.
---
Environment
| | |
|---|---|
| App | ChatGPT.app, bundle id com.openai.codex |
| Versions affected | 26.810.50856 (build 6644) and 26.810.52044 (build 6662) |
| Codex Framework | 151.0.7922.137 |
| OS | macOS 26.6 (25G70) |
| Hardware | Mac16,12 (MacBook Air, Apple M4), 16 GB RAM, arm64 |
| Code signing | Team 2DC432GLL2, SIP enabled |
Incident identifiers
ABB9BFB7-E22A-4327-BBBA-943F6B88C6C4F0C7CF4C-2E4D-462A-AFF1-7507DCBA41E4- Crash Reporter Key:
3BC8D0AF-8D22-F1E5-3609-041FD3753DFE
---
The actual error
Launching the binary directly from a terminal (ChatGPT.app/Contents/MacOS/ChatGPT) surfaces the error
that the crash reporter hides:
<--- Last few GCs --->
[pid:0x...] 6605 ms: Mark-Compact (reduce) 3912.4 (3927.5) -> 3912.4 (3927.2) MB,
pooled: 0.0 MB, 13.28 / 0.00 ms (average mu = 0.187, current mu = 0.001)
last resort; GC in old space requested
[pid:0x...] 6618 ms: Mark-Compact (reduce) 3912.4 (3927.2) -> 3912.4 (3927.0) MB,
pooled: 0.0 MB, 12.69 / 0.00 ms (average mu = 0.104, current mu = 0.001)
last resort; GC in old space requested
ERROR:owl/common/node_bindings.cc:109] OOM error in V8:
CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
Two separate runs reached 3887.9 MB at 5956 ms and 3912.4 MB at 6605 ms respectively. No<--- JS stacktrace ---> block is emitted, so the retaining path is not recoverable from the log alone.
Faulting stack
Identical, frame for frame and offset for offset, in every crash report collected, across both
builds:
0 <unsymbolized> (fatal handler)
...
6 v8::String::NewFromUtf8(v8::Isolate*, char const*, v8::NewStringType, int) + 328
7 node::StringDecoder::DecodeData(v8::Isolate*, char const*, unsigned long*) + 1028
8 node::StringDecoder::DecodeData(v8::Isolate*, char const*, unsigned long*) + 564
9 _register_external_reference_string_decoder(...) + 916
10-16 ??? (JIT frames)
...
20 node::InternalCallbackScope::Close() + 400
21 node::fs::FSReqPromise<...>::SelfSize() const + 636
22 node::fs::AfterInteger(uv_fs_s*) + 204
23 node::MakeLibuvRequestCallback<uv_fs_s, void (*)(uv_fs_s*)>::Wrapper(uv_fs_s*) + 204
24 uv__work_done + 172
25 uv__async_fork + 864
26 uv__io_poll + 1348
27 uv_run + 972
Read bottom-up: an async filesystem request completes, its JS callback runs, string decoding of the
result triggers the allocation that pushes the heap over the limit. The fatal handler fires inside thefs completion callback. That makes an fs read path in main-process startup the prime suspect, though
the specific call site is not identifiable without a heap snapshot.
Distinguishing this from the known report
There is an existing community report of build 26.810.50856 crashing after 1 to 3 minutes viacomputer-use worker-thread accumulation (~2.5 threads/sec, ~70 MB/sec). This is a different bug.
| | Known thread-leak report | This bug |
|---|---|---|
| Time to death | 1 to 3 minutes | 7 to 17 seconds |
| Thread count | grows unbounded | flat, 57 to 69 |
| computer-use threads in crash log | many | 0 or 1 |
| Allocation rate | ~70 MB/sec | ~600 MB/sec |
Thread counts measured across nine pre-intervention crash reports: 68, 65, 66, 69, 65, 67, 63, 65, 65.computer-use thread counts in the same nine: 0, 0, 1, 0, 0, 0, 0, 1, 1. Nothing accumulates.
Reproduction and bisection
Nine crash reports were produced on a single day with no user intervention, all with the identical
signature above, spanning both builds 6644 and 6662. The app binary was unmodified since installation,
so no app update coincides with onset. Six further crashes were then reproduced under controlled
conditions.
Hypotheses eliminated, each by direct test:
- App version. Identical crash on 6644 and 6662.
- Large session rollout files. The two outliers (8.19 MB and 7.31 MB
.jsonl, versus <1 MB for
all others) moved aside. Still crashed.
- Computer Use helper.
~/.codex/computer-use/removed entirely. Still crashed. - Stale helper processes. All
Codex Computer Use/SkyComputerUseClientprocesses killed.
Still crashed.
- Avatar overlay restore.
electron-avatar-overlay-openset false and
electron-remote-hosted-pip-task-visibility-state cleared. Still crashed.
The state bisection that isolated it:
| Test | CODEX_HOME | ~/Library/Application Support/Codex | Result |
|---|---|---|---|
| 1 | real | real | crash, ~7 s |
| 2 | empty | real | crash |
| 3 | real | empty | crash |
| 4 | empty | empty | survives, 1 min 7 s, RSS 614 MB falling to 340 MB |
Neither store alone is sufficient to trigger it and neither alone is sufficient to fix it. The two
stores appear to mirror the same poisoned data, so whichever survives re-seeds it. Clearing both
breaks the cycle.
Workaround
Quit the app, then move both state locations aside:
pkill -x ChatGPT; sleep 2
mkdir -p ~/chatgpt-fix
mv ~/Library/Application\ Support/Codex ~/chatgpt-fix/
mv ~/.codex/.codex-global-state.json ~/chatgpt-fix/
mv ~/.codex/cache ~/chatgpt-fix/
open -a ChatGPT
Important caveat observed in practice. After the move, the app still crashed four more times over
about three minutes while rebuilding its state, then stabilised on its own and has not crashed since.
Four subsequent launches, including a clean relaunch via Finder, all survived with RSS settling around
200 to 260 MB and trending down. Users applying this workaround should attempt several launches before
concluding it failed. Why the first launches after the wipe still crashed is not established.
~/.codex/sessions/, auth.json and plugins/ are untouched by the above, so history, login and
installed plugins survive.
---
Secondary bug found along the way: unbounded PiP bootstrap retry
Independent of the OOM, when the app runs against a fresh CODEX_HOME the Computer Use bootstrap
enters a retry storm with no backoff. One 30-second run logged 58 failures across many dispatch
threads:
RemoteHostedPIPContent CUAService bootstrap failed:
Error Domain=NSOSStatusErrorDomain Code=-1712 "errAETimeout: the AppleEvent timed out"
RemoteHostedPIPContent CUAService bootstrap failed:
Error Domain=RemoteHostedPIPContent Code=-10005 "Remote hosted PiP is unavailable."
Contributing factors and related observations:
sky.node-[RemoteHostedPIPContentService sendBootstrapToServiceWithProcessIdentifier:rendezvousPort:attempt:]
appears on a live thread in the crash reports, sending AppleEvents.
- The unified log shows
AESendMessage: returning procNotFound because destPort == NULLfor the helper
pid, i.e. the target process is gone or unreachable.
- TCC returned denied for
kTCCServiceAccessibilityfor this app (auth_value0), while
kTCCServiceScreenCapture was granted. Computer Use cannot function in that state, and the app does
not surface this to the user.
- Helper processes named
Codex Computer Usesurvive the parent's death and were observed still
running after the app exited, which likely makes the next launch's bootstrap fail too. This matches
the "leaves stale helpers" behaviour already reported separately.
Also seen roughly 200 ms before the OOM in one run, from the overlay renderer:
[electron-message-handler] Request failed method=fs/readFile
error={"code":-32603,"message":"No such file or directory (os error 2)"}
rendererWindowAppearance=avatarOverlay rendererWindowVisible=false
Given that the faulting stack is inside an fs completion callback, a failing fs/readFile from the
avatar overlay immediately prior is worth checking, though causation is not established.
---
Suggested next steps for triage
- Ship a
--heapsnapshot-near-heap-limitpath, or emit the<--- JS stacktrace --->block on main
process OOM. Right now the failure is undiagnosable from the client side.
- Add a bound and backoff to
RemoteHostedPIPContentServicebootstrap retries, and tear down helper
processes on parent exit.
- Add a size or shape guard on whatever startup path reads and string-decodes local state, so a
poisoned entry degrades instead of aborting the process.
- Surface denied Accessibility permission in the UI rather than failing silently.
2 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Same deterministic OOM here, on a newer build than the two in the report, so this is not fixed in 6892.
Environment
Signature — identical in every
~/Library/Logs/DiagnosticReports/ChatGPT-*.ips:Three of the crashes fault in a thread named
computer-useinstead ofV8Worker, otherwise identical.Growth is linear, ~105 MB/s in the Electron main process. Sampling RSS of
/Applications/ChatGPT.app/Contents/MacOS/ChatGPTevery 5 s from launch:Crash lands at 71–80 s after launch, every time.
Three things that did NOT help, each verified:
CODEX_HOME(CODEX_HOME=/tmp/empty /Applications/ChatGPT.app/Contents/MacOS/ChatGPT) reproduces the same linear leak and the same crash at 80 s. No plugins, no MCP servers, no sessions loaded.~/Library/Application Support/Codex,~/.codex/.codex-global-state.jsonand~/.codex/cacheaside, then four consecutive launches over ~7 minutes: all four crashed with the same OOM signature, no convergence. Reverted.--js-flags="--max-old-space-size=16384"is ignored; the process still dies around 6 GB RSS, same stack.Point 1 seems worth emphasizing: with an empty
CODEX_HOMEthere is no user data left to decode, yet the leak is unchanged. That argues against the stored-state theory and points at something in the startup path itself.Happy to run further instrumentation or provide a full
.ipsif useful.