macOS desktop: repeated `disk writes` resource-limit kills from runaway SQLite WAL checkpoint on unbounded logs_2.sqlite; stale SingletonLock then blocks relaunch
TL;DR
On macOS, the desktop app's background codex helper is repeatedly terminated by the OS disk writes resource monitor (jetsam / RLIMIT-style highwater kill), not by an in-app crash. Root cause: the local logging database ~/.codex/logs_2.sqlite has grown to ~2.8 GB and the process spends effectively all of its time in sqlite3_wal_checkpoint_v2 → pwrite, dirtying tens of GB of file-backed memory (worst observed: 34.36 GB of file-backed memory dirtied over 23,191 s, ~1.48 MB/s sustained). macOS counts this against a per-process disk-write highwater limit and kills the process.
Because the kill is unclean, it leaves behind:
- a stale
SingletonLockin~/Library/Application Support/Codex/pointing to a dead PID, and - orphaned helper processes (
browser_crashpad_handler×2,bare-modifier-monitor) reparented to PID 1,
which then prevent the app from relaunching ("nothing happens when I open it") until they are manually cleared.
This is two related defects: (A) the runaway-write termination, and (B) the failure to recover cleanly on next launch.
---
Environment
| | |
|---|---|
| Hardware | Mac16,8 (Apple Silicon, arm64e), 12 CPUs, 24 GB RAM |
| OS | macOS 26.4 (build 25E246) |
| App | ChatGPT desktop (formerly "Codex"), app version 26.707.41301 |
| Framework | Codex Framework.framework version 150.0.7871.115 (previously .101 — see note below) |
| Codesigning ID / Team | codex / 2DC432GLL2 |
| Resource Coalition | com.openai.codex |
Note: crash reports show the bundle path migrating from /Applications/Codex.app/... (≤ Jul 9) to /Applications/ChatGPT.app/... (≥ Jul 10), i.e. a rebrand/update happened mid-window. Both bundles exhibit the identical failure signature.
---
Defect A — OS terminates the process for excessive disk writes (runaway SQLite WAL checkpoint)
OS-level termination signature
Every one of the last 9 diagnostic reports is a disk writes Microstackshots report (Action taken: none), i.e. the macOS disk-write resource monitor, not a segfault/abort. Most recent report (codex_2026-07-11-065626):
Command: codex
Path: /Applications/ChatGPT.app/Contents/Resources/codex
Parent: UNKNOWN [98060]
PID: 98180
Event: disk writes
Action taken: none
Writes: 34.36 GB of file backed memory dirtied over 23191 seconds
(1481.57 KB per second average),
exceeding limit of 397.68 KB per second over 86400 seconds
Writes limit: 34.36 GB
Free disk space: 6689.84 MB / 460.43 GB, low space threshold 3072 MB
The write path — SQLite WAL checkpoint
The heaviest stack for the terminated process points squarely at SQLite checkpointing (the binary is Rust; symbols are partial but the SQLite frames are clear):
_pthread_start
std::sys::backtrace::__rust_begin_short_backtrace
sqlite3_exec
sqlite3_step
sqlite3_wal_checkpoint_v2
??? (codex)
pwrite ← libsystem_kernel
The write target — unbounded local logging DB
On disk, the logging database is enormous and actively growing while the app runs:
2.6–2.8 GB ~/.codex/logs_2.sqlite (+ ~40 MB logs_2.sqlite-wal, live)
8.7 GB ~/.codex/sessions
271 MB ~/.codex/sqlite
13 GB ~/.codex (total)
A multi-GB SQLite DB under continuous WAL checkpointing memory-maps and re-dirties a large working set on every checkpoint; macOS accounts those dirtied file-backed pages against the process's disk-write highwater limit, so the process is killed on a timer regardless of available RAM. (At the time I write this, free RAM is 81%, yet the process was still killed — this is a write-rate, not a memory-exhaustion, limit.)
Recurrence & escalation (last 9 events)
The macOS monitor re-arms with a doubling highwater after each kill, so the "Writes limit" climbs 2 GB → 8 GB → 34 GB across successive terminations. Free disk space is drawn down in parallel.
| Local time | Command | PID / Parent | Writes limit tripped | Free disk | Bundle |
|---|---|---|---|---|---|
| 2026-07-11 06:56 | codex | 98180 / 98060 | 34.36 GB | 6.69 GB | ChatGPT.app |
| 2026-07-11 00:29 | ChatGPT | 98060 / 1 | 8.59 GB | 42.38 GB | ChatGPT.app |
| 2026-07-10 21:48 | codex | 98180 / 98060 | 2.15 GB | 14.13 GB | ChatGPT.app |
| 2026-07-09 21:14 | ChatGPT | 45816 / 1 | 2.15 GB | 11.46 GB | ChatGPT.app |
| 2026-07-09 07:59 | codex | 42626 / 42316 | 8.59 GB | 15.79 GB | Codex.app |
| 2026-07-09 05:32 | codex | 19673 / 19614 | 2.15 GB | 25.17 GB | Codex.app |
| 2026-07-06 21:36 | codex | 88485 / 88385 | 2.15 GB | — | Codex.app |
| 2026-07-06 19:56 | codex | 88485 / 88385 | 2.15 GB | — | Codex.app |
| 2026-07-05 22:50 | codex | 33712 / 33537 | 2.15 GB | 14.88 GB | Codex.app |
Note the parent/child pairing: the main ChatGPT/Codex process (parent PID 1) and its long-lived codex helper (Contents/Resources/codex) are both killed under the same signature. In the latest event the helper's parent (98060) is exactly the main process that was killed 6.4 h earlier — so the helper kept writing after its parent died.
---
Defect B — unclean kill blocks relaunch (stale singleton + orphaned helpers)
After the resource-limit kill, the app would not reopen (open -a ChatGPT returns 0 but no process appears). Two leftovers were responsible:
1. Stale Chromium singleton lock in ~/Library/Application Support/Codex/:
SingletonLock -> ZimingWangs-MacBook-Pro-4.local-98060 # PID 98060 no longer exists
SingletonCookie -> 10769481914328928945
SingletonSocket -> /var/folders/.../T/com.openai.codex.fmOZMW/SingletonSocket
98060 was the PID killed at 00:29; the lock was never released, and the new instance would not take over the stale lock.
2. Orphaned helper processes (parent reparented to PID 1) that survived the kill:
PID PPID ELAPSED COMM
17301 1 23:21:47 .../Codex Framework.framework/Versions/150.0.7871.101/Helpers/browser_crashpad_handler
17303 1 23:21:47 .../browser_crashpad_handler
29616 1 03:57:55 .../ChatGPT.app/Contents/Resources/native/bare-modifier-monitor
These handlers persisted for ~23 h after their parent died, still referencing the previous framework version (150.0.7871.101) even though the on-disk framework had already updated to .115.
Manual recovery that worked
# 1. reap the orphaned helpers (all had PPID==1)
kill 17301 17303 29616
# 2. remove the stale singleton artifacts (lock holder PID confirmed dead)
cd ~/Library/Application\ Support/Codex
rm -f SingletonLock SingletonCookie SingletonSocket
# 3. relaunch
open -a ChatGPT
The app then started normally and recreated a healthy SingletonLock -> ...-<live PID>. Full Chromium process tree (main + services + renderers) came up; no new crash report was generated.
---
Suggested fixes
Defect A (root cause):
- Bound
logs_2.sqlite: enforce a size/row cap with periodic pruning or rotation; a local log DB should not be allowed to reach multiple GB. - Avoid full-WAL-checkpoint storms: use
wal_autocheckpointtuning /PRAGMA journal_size_limit, orTRUNCATE-mode checkpoints on a bounded cadence rather than continuouswal_checkpoint_v2under a huge WAL. - Consider throttling log-write volume at the source; 34 GB dirtied in 6.4 h from a logging path is disproportionate.
- Also bound
~/.codex/sessions(8.7 GB here) with retention/archival limits.
Defect B (resilience):
- On startup, detect and clear a
SingletonLockwhose recorded host matches the local host but whose PID is dead (standard stale-lock recovery), instead of silently failing to launch. - Reap the app's own orphaned helpers (
browser_crashpad_handler,bare-modifier-monitor) on next launch, or make the singleton takeover robust to their presence.
---
Relationship to existing issues
This report corroborates and sharpens several open issues, but adds the concrete OS disk writes termination signature and the SQLite-WAL write path, which I did not find documented:
- #26869 — "Codex Desktop app-server leaks child processes and writes excessive logs after crash/restart" — closest match; this report supplies the exact write mechanism (SQLite WAL checkpoint on
logs_2.sqlite) and the OS-kill signature behind "excessive logs", plus the relaunch-blocking singleton/orphan detail. - #30408 — MCP server process leak (9+ GB RSS).
- #25744 — macOS helper/zombie accumulation causing HID/WindowServer stalls.
- #21984 / #20883 — MCP-per-session eager start / process-pool proposal.
If maintainers prefer, Defect A can fold into #26869 and Defect B can be filed separately as a launch-resilience bug.
---
Diagnostic commands (for reproduction / triage)
# OS-kill reports (this is the ground truth — look for "Event: disk writes")
ls -lt /Library/Logs/DiagnosticReports/*[Cc]odex* /Library/Logs/DiagnosticReports/*[Cc]hatGPT*
grep -E '^(Command|Event|Writes:|Writes limit|Parent|Free disk space):' <report>.diag
# write target sizes
du -sh ~/.codex ~/.codex/logs_2.sqlite ~/.codex/sessions
# stale singleton after an unclean kill
ls -la ~/Library/Application\ Support/Codex/Singleton*
# orphaned helpers (PPID==1) left behind
ps -eo pid,ppid,etime,comm | grep -Ei 'Codex Framework|bare-modifier-monitor'
Reporter environment captured 2026-07-11. Diagnostic reports available on request (Microstackshots disk writes .diag files, Jul 5–11, 2026).
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗