macOS desktop: repeated `disk writes` resource-limit kills from runaway SQLite WAL checkpoint on unbounded logs_2.sqlite; stale SingletonLock then blocks relaunch

Open 💬 1 comment Opened Jul 11, 2026 by ZenAlexa

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 SingletonLock in ~/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_autocheckpoint tuning / PRAGMA journal_size_limit, or TRUNCATE-mode checkpoints on a bounded cadence rather than continuous wal_checkpoint_v2 under 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 SingletonLock whose 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).

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗