#15619: fix: clean up orphan LaunchAgent plist on bootstrap failure
gateway
stale
size: S
Cluster:
Gateway and macOS Improvements
## Summary
Fixes #14315
- When `launchctl bootstrap` fails during onboarding (e.g., user denies macOS security prompt), the plist file was left on disk with no cleanup path
- Now attempts `launchctl bootout` and removes the plist file before throwing the error
- Both cleanup operations silently catch errors (file may not exist, service may not be loaded)
## Changes
- `src/daemon/launchd.ts`: 3 lines added — bootout + unlink on bootstrap failure
- `src/daemon/launchd.test.ts`: New test verifying plist cleanup on bootstrap failure
## Test plan
- [x] New test: "cleans up plist file when bootstrap fails" — creates failing launchctl stub, verifies plist is removed
- [x] All 15 launchd tests pass
- [x] No existing test assertions changed
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR updates the macOS LaunchAgent install flow to clean up on `launchctl bootstrap` failure: it attempts a `launchctl bootout` and unlinks the generated plist before rethrowing the bootstrap error. It also adds a regression test that stubs `launchctl` to fail specifically on `bootstrap` and asserts the plist is removed afterward.
The change is localized to `src/daemon/launchd.ts`’s `installLaunchAgent` path and extends the existing launchctl-stubbing test harness in `src/daemon/launchd.test.ts`.
<h3>Confidence Score: 4/5</h3>
- Mostly safe to merge once the Windows test hermeticity issue is addressed.
- Core runtime change is small and well-scoped, but the new test likely won’t correctly stub `launchctl` on Windows due to writing an extensionless batch file while execution relies on `shell: true` PATH resolution. Also noted a misleading dead `.catch()` in the cleanup path.
- src/daemon/launchd.test.ts (win32 stub), src/daemon/launchd.ts (bootstrap failure cleanup)
<sub>Last reviewed commit: 20dabad</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#11327: fix(launchd): reload plist from disk on restartLaunchAgent
by caiop91 · 2026-02-07
82.6%
#19857: fix(launchd): self-heal restart when service is unloaded
by vibecodooor · 2026-02-18
79.1%
#18236: macOS daemon: bootstrap LaunchAgent on gateway start after stop
by agisilaos · 2026-02-16
77.9%
#8642: fix: improve launchctl bootstrap error messages for GUI domain issues
by dbottme · 2026-02-04
76.2%
#4709: fix(daemon): include user bin dirs in macOS LaunchAgent PATH
by ekson73 · 2026-01-30
76.0%
#19879: Feat/foropenclaw bootstrapfiles clean
by akyourowngames · 2026-02-18
75.6%
#16845: fix(daemon): gateway auto-restart on SIGTERM + agent restart guidel...
by kiminbean · 2026-02-15
75.5%
#20272: fix: LaunchAgent KeepAlive causes restart loop (fixes #20257)
by MisterGuy420 · 2026-02-18
75.4%
#22224: fix(launchd/macos): prevent restart loop by using KeepAlive.Success...
by ashiabbott · 2026-02-20
75.2%
#20390: fix(daemon): fall back to /tmp for launchd logs on removable volumes
by lemoz · 2026-02-18
75.2%