Codex-created launchctl restart job becomes a keepalive loop that repeatedly terminates ChatGPT

Open 💬 4 comments Opened Jul 11, 2026 by amarcher
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What version of Codex CLI is running?

codex-cli 0.144.1

What subscription do you have?

ChatGPT subscription (the exact tier is not exposed by the CLI).

Which model were you using?

gpt-5.6-sol

What platform is your computer?

Darwin 25.5.0 arm64 arm — macOS 26.5 (25F71)

What terminal emulator and version are you using?

iTerm2 3.6.11, no multiplexer.

Codex doctor report

The full redacted report and logs were uploaded via /feedback.

Uploaded thread: 019f4f25-e935-7231-90c3-e2449d1b9bf7

Relevant summary:

{
  "overallStatus": "ok",
  "codexVersion": "0.144.1",
  "app_server.status": {
    "status": "ok",
    "summary": "background server is not running",
    "mode": "ephemeral",
    "pid_file": "missing"
  },
  "installation": {
    "status": "ok",
    "summary": "installation looks consistent"
  },
  "network.websocket_reachability": {
    "status": "ok",
    "summary": "Responses WebSocket handshake succeeded"
  }
}

What issue are you seeing?

ChatGPT/Codex desktop 26.707.31428 (build 5059, bundle ID com.openai.codex) exits within seconds of launching and opening a workspace or resuming a thread.

Each attempt leaves orphaned browser_crashpad_handler and bare-modifier-monitor processes. There is no Crashpad minidump and no conventional macOS crash report, so this looks more like an unintended clean exit or host shutdown than a normal native crash.

A desktop app-server orphan remained alive for hours and held the remote-control WebSocket. New desktop app-server launches then logged:

HTTP 409 Conflict
{"detail":"Remote app server already online"}

The same orphan was not reported by codex doctor --json, which said the background server was not running. Stopping only that orphan removed the 409, but the desktop app still exited immediately, so the conflict is real but not the entire failure.

There is also a launcher/rebrand mismatch: codex app <path> does not recognize the installed /Applications/ChatGPT.app despite its com.openai.codex bundle ID. It says “Codex Desktop not found,” downloads the installer, and still does not leave a usable desktop app. This overlaps with #31944; the stale remote-control behavior overlaps with #28862.

The impact is larger than a desktop crash because official Browser docs say Browser is available in ChatGPT web/desktop but not Codex CLI or the IDE extension. The Chrome extension/native host is installed, healthy, and has successfully connected as codex-chrome-extension-sidepanel, but a CLI session cannot use it. Once the desktop app exits, there is no supported browser-verification path.

What steps can reproduce the bug?

  1. Install and enable ChatGPT for Chrome.
  2. Launch ChatGPT desktop 26.707.31428 on macOS.
  3. Open a local workspace or resume an existing Codex thread.
  4. Observe the main desktop process exit within seconds.
  5. Repeat and observe additional orphaned crashpad and modifier-monitor helpers.
  6. Inspect Codex logs: when the stale app-server is present, the new desktop server receives 409 Remote app server already online.
  7. Stop the stale app-server and repeat: the 409 disappears, but the main app still exits.
  8. Run codex doctor --json: it reports no background server even when the orphan is active.
  9. Run codex app <workspace>: it fails to recognize /Applications/ChatGPT.app and attempts another installer download.

Uploaded diagnostic thread: 019f4f25-e935-7231-90c3-e2449d1b9bf7.

What is the expected behavior?

The desktop app should remain open, should own or reuse exactly one remote-control app-server, and should clean up its helpers on exit. codex doctor should detect any live desktop app-server that can cause a 409. codex app should recognize the ChatGPT-branded app by bundle ID. If Browser remains unsupported in CLI, CLI should immediately explain that limitation and provide a supported fallback instead of sending users through extension restart/reinstall loops.

Additional information

Environment:

  • ChatGPT desktop: 26.707.31428, build 5059
  • Codex CLI: 0.144.1
  • Chrome: 150.0.7871.115
  • ChatGPT for Chrome: 1.2.27203.26575
  • macOS: 26.5 (25F71)

Related issues: #31944 and #28862.

View original on GitHub ↗

4 Comments

github-actions[bot] contributor · 1 month ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #31423

Powered by Codex Action

amarcher · 1 month ago

Closing after root-cause correction above; the actionable product issues remain tracked in #31944, #28862, and the uploaded feedback thread.

amarcher · 1 month ago

Root cause and tested workaround

This was not a native Electron crash. A previous Codex desktop session created a submitted launchd job while trying to restart itself after changing autonomy/notification settings:

com.openai.codex-autonomy-restart

The job was unintentionally inferred as keepalive. At diagnosis time, launchctl print showed:

state = spawn scheduled
runs = 4642
last exit code = 127
properties = keepalive | inferred program

It repeatedly executed /private/tmp/codex-autonomy-restart.sh. The script did this on every run:

sleep 2
killall -TERM ChatGPT 2>/dev/null || true

It then tried to use /Applications/Codex.app/Contents/Resources/cua_node/bin/node. That path no longer existed after the ChatGPT rebrand/installer behavior, so the script exited 127 before reopening anything. Because launchd considered the submitted job keepalive, it immediately scheduled another run and killed every new ChatGPT process. This exactly explains the clean exits, absent crash dumps, and accumulating orphan helpers.

Tested workaround:

launchctl remove com.openai.codex-autonomy-restart

Verification:

launchctl print "gui/$(id -u)/com.openai.codex-autonomy-restart"
# Expected: Could not find service

open -a ChatGPT
pgrep -alf '^/Applications/ChatGPT.app/Contents/MacOS/ChatGPT'
# The main process now remains alive beyond the former 10-second kill cycle.

The temporary script and its backup can be left in place; they are inert once the submitted launchd job is removed. No preferences or conversation data need to be deleted.

Why this remains worth tracking: the kill loop was created by a Codex agent's approved self-restart command using launchctl submit without safe one-shot semantics or cleanup. The launcher/rebrand mismatch (#31944) then made the restart script fail permanently and amplified the mistake into a keepalive termination loop. The stale remote app-server/409 behavior is separately related to #28862.

Uploaded diagnostics: 019f4f25-e935-7231-90c3-e2449d1b9bf7.

jeremy9682 · 1 month ago

Additional independent recurrence on a newer macOS build, with evidence that may help separate the confirmed launchd bug from a possible recovery/idempotency bug.

Environment:

  • ChatGPT/Codex App 26.707.72221 build 5307
  • bundled codex-cli 0.144.2
  • macOS 26.5.1 build 25F80, arm64

Confirmed sequence:

  1. One Codex thread explicitly executed a launchctl submit host-restart helper at 19:11:05 local time. The helper slept, quit ChatGPT, reopened it, and exited.
  2. Live launchd state showed type=Submitted, OnDemand=false, last exit code=0; runs increased from 59 to 64 within seconds.
  3. The first label was externally removed at 19:25:03 and confirmed absent.
  4. After the same Codex thread was continued, it explicitly repeated the same design under a second label at 19:30:11.
  5. Unified logs show 96 end/relaunch events for the first job, 51 for the second, and 123 ChatGPT service exits/removals during the captured window.

New recovery/idempotency evidence:

  • The first label, confirmed removed at 19:25:03, reappeared at 19:36:27.
  • The persisted rollout contains only the original explicit submit tool call for that first label; no second explicit call is recorded.
  • The most plausible explanation is app-server resume/recovery re-executing a prior side-effecting call, but I do not have a direct replay event or second launchctl parent record. Please treat this as a suspected recovery path, not a proven mechanism.

Identifiers for internal tracing:

  • thread: 019f6525-1db4-7252-853b-ad2c682dc368
  • first restart turn: 019f6578-78da-7643-b1d7-ecddb4b2eaff
  • first submit call: call_1AV4OoDM2vbueksMtZThtqvl
  • second restart turn: 019f6588-aa16-7951-8428-e5747dba6010
  • second submit call: call_RbNCFULCDyV4whB5g3YVBIcS

Two product-level protections seem necessary:

  1. Do not let the agent use legacy launchctl submit as a one-shot host restart helper; provide a supported one-shot restart operation with TTL, cleanup, and postcondition checks.
  2. Persist at-most-once completion by tool call_id across app-server restarts. If a call outcome is unknown, reconcile external state before retrying rather than executing it automatically.

I opened #33327 before the duplicate detector pointed here. I am closing that report in favor of this existing issue.