ChatGPT Desktop for macOS: deterministic main-process V8 heap OOM at startup (builds 6644 and 6662)
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
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 the
fs 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 via
computer-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-statecleared. 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
kTCCServiceScreenCapturewas 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.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
No repository files or tests are named. Start with the desktop main-process startup path around the fs/readFile failure and the RemoteHostedPIPContentService bootstrap entry point; reproduce with both state locations present and capture a heap snapshot or OOM stack. Done means the startup OOM is diagnosable and the implicated state or retry path no longer causes unbounded growth.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- electron, javascript, macos
- Domain
- desktop, performance
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100