Skip to content

[Bug]: macOS LaunchAgent repair kickstarts already-loaded running gateway #77428

Description

@ramitrkar-hash

Summary

On macOS, repairLaunchAgentBootstrap() still appears to kickstart the OpenClaw gateway LaunchAgent when launchctl bootstrap reports that the service is already loaded. If the service is already loaded and running, repair should return success instead of forcing a kickstart/restart.

This is adjacent to, but narrower than, #40905. That issue covered openclaw gateway restart re-bootstrap behavior. This report is specifically about the repair/install path's already-loaded branch.

Environment

  • OpenClaw: 2026.5.3-1 (2eae30e)
  • Platform: macOS 26.4.1 arm64
  • Node: 22.22.1
  • Gateway service: LaunchAgent ai.openclaw.gateway
  • Gateway path: /opt/homebrew/lib/node_modules/openclaw/dist/index.js gateway --port 18789

Current Behavior

In the current compiled launchd bundle:

async function repairLaunchAgentBootstrap(args) {
  ...
  const boot = await execLaunchctl([
    "bootstrap",
    domain,
    plistPath
  ]);
  let repairStatus = "repaired";
  if (boot.code !== 0) {
    const detail = (boot.stderr || boot.stdout).trim();
    if (!isLaunchctlAlreadyLoaded(boot)) return {
      ok: false,
      status: "bootstrap-failed",
      detail: detail || void 0
    };
    repairStatus = "already-loaded";
  }
  if (repairStatus === "repaired") return {
    ok: true,
    status: repairStatus
  };
  const kick = await execLaunchctl(["kickstart", serviceTarget]);
  ...
}

So if bootstrap fails only because the LaunchAgent is already loaded, the code proceeds to:

launchctl kickstart gui/$UID/ai.openclaw.gateway

Expected Behavior

If bootstrap reports already loaded, repairLaunchAgentBootstrap() should inspect the runtime state. If the loaded service is already running, it should return success:

{"ok":true,"status":"already-loaded"}

It should only kickstart if the service is already loaded but not running or otherwise unhealthy.

Why This Matters

The repair path can be used during update/doctor/install flows. Unconditionally kickstarting an already-running service can:

  • interrupt an otherwise healthy gateway
  • disconnect WebUI/Discord sessions unnecessarily
  • fail under macOS permission/context constraints even when no repair was needed
  • make repair/install behavior look broken while the service is actually fine

Local Patch Previously Used

We have carried this local patch for earlier OpenClaw versions and it still appears applicable in 2026.5.3-1.

Suggested minimal upstream change:

if (repairStatus === "already-loaded") {
  const runtime = await readLaunchAgentRuntime(env).catch(() => null);
  if (runtime?.status === "running") return {
    ok: true,
    status: repairStatus
  };
}
const kick = await execLaunchctl(["kickstart", serviceTarget]);

This keeps the existing kickstart behavior for non-running already-loaded services, while avoiding an unnecessary restart when the service is already loaded and running.

Validation / Local Evidence

Current 2026.5.3-1 code still contains the unconditional already-loaded -> kickstart path:

/opt/homebrew/lib/node_modules/openclaw/dist/launchd-BVs6hych.js
repairLaunchAgentBootstrap(...)
repairStatus = "already-loaded"
const kick = await execLaunchctl(["kickstart", serviceTarget])

The gateway itself is healthy after normal restart:

OpenClaw status --all:
Gateway service LaunchAgent installed · loaded · running
Gateway reachable on ws://127.0.0.1:18789

Suggested Upstream Fix

In repairLaunchAgentBootstrap():

  1. Detect already-loaded.
  2. Call readLaunchAgentRuntime(env).
  3. If runtime status is running, return success without kickstart.
  4. Keep the existing kickstart fallback only for loaded-but-not-running states.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions