openclaw - 💡(How to fix) Fix gateway restart mode=reload can leave the LaunchAgent deregistered (bootout→bootstrap race, no fallback)

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

On macOS, when the gateway restarts in mode=reload, the launchd handoff can fail with Bootstrap failed: 5: Input/output error and leave the LaunchAgent deregistered with no auto-recovery — even with KeepAlive=true. The gateway stays down until a manual launchctl bootstrap.

Error Message

On macOS, when the gateway restarts in mode=reload, the launchd handoff can fail with Bootstrap failed: 5: Input/output error and leave the LaunchAgent deregistered with no auto-recovery — even with KeepAlive=true. The gateway stays down until a manual launchctl bootstrap. launchctl bootout returns 0 immediately, but launchd processes the unload asynchronously. The immediately-following bootstrap can hit the service while it is still registered / in transition and fail with 5: Input/output error (EIO). Bootstrap failed: 5: Input/output error

Root Cause

The reload handoff script (generated in src/daemon/launchd-restart-handoff.ts, mode === "reload") runs:

launchctl enable "$service_target"
launchctl bootout "$service_target" >/dev/null 2>&1 || true
if launchctl bootstrap "$domain" "$plist_path"; then
  status=0
else
  status=$?
fi

launchctl bootout returns 0 immediately, but launchd processes the unload asynchronously. The immediately-following bootstrap can hit the service while it is still registered / in transition and fail with 5: Input/output error (EIO).

Two compounding problems:

  1. No fallback. Unlike the kickstart and start-on-demand templates (which retry with launchctl kickstart -k on failure), the reload template has no fallback path.
  2. No auto-recovery. Because the bootout succeeded, launchd treats the service as cleanly deregistered (not crashed), so KeepAlive=true does not restart it.

Net effect: the gateway is left with no registered label and never comes back on its own.

Fix Action

Fix / Workaround

Manual recovery (workaround)

Code Example

launchctl enable "$service_target"
launchctl bootout "$service_target" >/dev/null 2>&1 || true
if launchctl bootstrap "$domain" "$plist_path"; then
  status=0
else
  status=$?
fi

---

openclaw restart attempt source=launchd-handoff mode=reload target=gui/<uid>/<label> waitPid=...
Bootstrap failed: 5: Input/output error
openclaw restart failed source=launchd-handoff mode=reload status=5

---

launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/<label>.plist
RAW_BUFFERClick to expand / collapse

Summary

On macOS, when the gateway restarts in mode=reload, the launchd handoff can fail with Bootstrap failed: 5: Input/output error and leave the LaunchAgent deregistered with no auto-recovery — even with KeepAlive=true. The gateway stays down until a manual launchctl bootstrap.

Environment

  • OpenClaw 2026.5.18
  • macOS, LaunchAgent under gui/<uid>
  • Node 22

Root cause

The reload handoff script (generated in src/daemon/launchd-restart-handoff.ts, mode === "reload") runs:

launchctl enable "$service_target"
launchctl bootout "$service_target" >/dev/null 2>&1 || true
if launchctl bootstrap "$domain" "$plist_path"; then
  status=0
else
  status=$?
fi

launchctl bootout returns 0 immediately, but launchd processes the unload asynchronously. The immediately-following bootstrap can hit the service while it is still registered / in transition and fail with 5: Input/output error (EIO).

Two compounding problems:

  1. No fallback. Unlike the kickstart and start-on-demand templates (which retry with launchctl kickstart -k on failure), the reload template has no fallback path.
  2. No auto-recovery. Because the bootout succeeded, launchd treats the service as cleanly deregistered (not crashed), so KeepAlive=true does not restart it.

Net effect: the gateway is left with no registered label and never comes back on its own.

Observed log (gateway-restart.log)

openclaw restart attempt source=launchd-handoff mode=reload target=gui/<uid>/<label> waitPid=...
Bootstrap failed: 5: Input/output error
openclaw restart failed source=launchd-handoff mode=reload status=5

Trigger

mode=reload is selected when rewriteLaunchAgentPlistForRestart detects drift between the on-disk plist and the regenerated one. A stale OPENCLAW_SERVICE_VERSION in the generated env file after an upgrade is enough to change the service description (plist Comment), which flips the restart into the fragile reload path on every config change that requires a channel reload. So once the env file goes stale post-upgrade, the next channel-config reload reliably knocks the gateway offline.

Suggested fix

Make mode=reload resilient — any one of:

  1. Replace bootout + bootstrap with launchctl kickstart -k "$service_target" (restarts in place, no unload required), or
  2. Poll launchctl print "$service_target" until it fails (confirming the unload actually completed) before calling bootstrap, or
  3. Give reload the same kickstart -k fallback the other templates already have.

Manual recovery (workaround)

launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/<label>.plist

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix gateway restart mode=reload can leave the LaunchAgent deregistered (bootout→bootstrap race, no fallback)