#20272: fix: LaunchAgent KeepAlive causes restart loop (fixes #20257)
app: macos
gateway
size: XS
trusted-contributor
Cluster:
Gateway Restart Improvements
## Bug Summary
When both LaunchAgent (KeepAlive: true) and the App's GatewayLaunchAgentManager manage the gateway lifecycle, they conflict — causing a restart loop, duplicate processes, and 100% CPU.
This is because KeepAlive: true tells launchd to restart the gateway whenever it exits (for any reason). Combined with the App's periodic SIGUSR1 signals (issue #10600), this creates a continuous restart loop.
## Root Cause
- `KeepAlive: true` in the LaunchAgent plist causes launchd to restart gateway on every exit
- App sends periodic SIGUSR1 signals every 8-11 minutes (issue #10600)
- Each SIGUSR1 triggers gateway restart, which launchd immediately restarts due to KeepAlive: true
- Results in continuous restart loop, duplicate processes, 100% CPU
## Fix
1. Changed `KeepAlive: true` to `KeepAlive: { SuccessfulExit: false }` — only restart on crash (non-zero exit), not on intentional stop
2. Added `ThrottleInterval: 5` to prevent exponential backoff on crash loops (related to issue #4632)
## Testing
- [x] pnpm install
- [x] pnpm build
- [x] pnpm check (format + lint + typecheck)
- [x] pnpm test (launchd tests pass)
---
**AI-assisted code** - This fix was generated by an automated bug-fix agent.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Changes the LaunchAgent `KeepAlive` setting from `true` to `{ SuccessfulExit: false }` and adds `ThrottleInterval: 5` to prevent restart loops caused by launchd restarting the gateway on every exit (including intentional SIGUSR1-triggered restarts). The template is also reformatted from a single-line string to a multi-line template literal for readability.
- **Service audit regression**: `src/daemon/service-audit.ts:173` uses a regex that only matches `KeepAlive` followed by `<true/>`. After this change, the plist uses a dict-based `KeepAlive`, so the audit will emit false-positive `"LaunchAgent is missing KeepAlive=true"` warnings for every correctly-configured installation. The audit check needs to be updated to accept the new format.
- **macOS app divergence**: `apps/macos/Sources/OpenClaw/LaunchAgentManager.swift:44` still generates `KeepAlive: true` in its own plist. If the macOS app's LaunchAgent has the same restart-loop issue, it should be updated as well for consistency.
<h3>Confidence Score: 2/5</h3>
- This PR introduces a regression in the service audit system that will produce false-positive warnings for all installations
- The core KeepAlive and ThrottleInterval changes are correct and well-motivated, but the PR does not update the service-audit.ts regex that validates plist contents. After this change, every correctly-configured installation will be flagged with a spurious 'LaunchAgent is missing KeepAlive=true' warning. This is a functional regression that needs to be addressed before merging.
- `src/daemon/service-audit.ts` needs its KeepAlive regex updated to accept the new dict-based format. `apps/macos/Sources/OpenClaw/LaunchAgentManager.swift` may also need the same KeepAlive change for consistency.
<sub>Last reviewed commit: 34d8426</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#22224: fix(launchd/macos): prevent restart loop by using KeepAlive.Success...
by ashiabbott · 2026-02-20
89.1%
#16845: fix(daemon): gateway auto-restart on SIGTERM + agent restart guidel...
by kiminbean · 2026-02-15
85.1%
#11327: fix(launchd): reload plist from disk on restartLaunchAgent
by caiop91 · 2026-02-07
78.3%
#21591: fix(update): prevent double restart when refreshing service env
by irchelper · 2026-02-20
77.9%
#10182: fix: skip non-openclaw LaunchAgents in doctor gateway scan
by Yida-Dev · 2026-02-06
77.6%
#8260: fix(macOS): gateway readiness detection + reversible Configure later
by xksteven · 2026-02-03
77.2%
#13084: fix(daemon): multi-layer defense against zombie gateway processes
by openperf · 2026-02-10
77.1%
#23584: fix(daemon): improve gateway service detection to avoid false posit...
by mohandshamada · 2026-02-22
77.0%
#22304: Gateway: fix launchd start after stop
by apethree · 2026-02-21
77.0%
#19857: fix(launchd): self-heal restart when service is unloaded
by vibecodooor · 2026-02-18
76.9%