nikivdev/code · error · anyhow::Error

launchctl bootstrap failed: {}

Error message

launchctl bootstrap failed: {}

What it means

install_launch_agent registers the supervisor as a macOS launchd agent by running `launchctl bootstrap <domain> <plist>`. If launchctl exits non-zero, the stderr is surfaced in this error. Typically means the plist is invalid, the service is already bootstrapped, or the domain-target is wrong.

Source

Thrown at src/supervisor.rs:571

    let plist_path = launch_agent_plist_path()?;
    let log_path = supervisor_log_path().ok();
    let plist = launch_agent_plist(socket_path, boot, log_path.as_deref())?;
    fs::write(&plist_path, plist)
        .with_context(|| format!("failed to write {}", plist_path.display()))?;

    let domain = launch_agent_domain();
    let target = launch_agent_target();

    let _ = Command::new("launchctl")
        .args(["bootout", &domain, plist_path.to_string_lossy().as_ref()])
        .output();

    let output = Command::new("launchctl")
        .args(["bootstrap", &domain, plist_path.to_string_lossy().as_ref()])
        .output()
        .context("failed to bootstrap launch agent")?;
    if !output.status.success() {
        bail!(
            "launchctl bootstrap failed: {}",
            String::from_utf8_lossy(&output.stderr)
        );
    }

    let _ = Command::new("launchctl").args(["enable", &target]).output();

    let output = Command::new("launchctl")
        .args(["kickstart", "-k", &target])
        .output()
        .context("failed to kickstart launch agent")?;
    if !output.status.success() {
        bail!(
            "launchctl kickstart failed: {}",
            String::from_utf8_lossy(&output.stderr)
        );
    }

View on GitHub (pinned to a747e741ae)

Solutions

  1. If the agent is already loaded, run `launchctl bootout <domain>/<plist>` first, then retry bootstrap.
  2. Check the stderr in the error: "already bootstrapped" means skip bootstrap and just kickstart.
  3. Verify the plist file exists and is valid XML (plutil -lint <plist>).
  4. Ensure you're in a GUI login session (not plain SSH) or use the correct domain target for your context.

Example fix

// before
launchctl bootstrap gui/$UID ~/Library/LaunchAgents/app.myapp.supervisor.plist
// Bootstrap failed: 5: Input/output error (already loaded)
// after
launchctl bootout gui/$UID/app.myapp.supervisor || true
launchctl bootstrap gui/$UID ~/Library/LaunchAgents/app.myapp.supervisor.plist
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight on macOS: lint plist and skip if already bootstrapped
import { execSync } from 'node:child_process';
if (process.platform === 'darwin') {
  execSync(`plutil -lint ${plistPath}`); // throws if malformed
  const loaded = execSync(`launchctl print gui/$(id -u)/${label} 2>&1 || true`).toString();
  if (!loaded.includes('Could not find')) {
    console.log('Agent already bootstrapped; skipping bootstrap.');
  }
}

Try / catch

try {
  await supervisorInstallLaunchAgent();
} catch (e) {
  const msg = String(e);
  if (msg.includes('launchctl bootstrap failed')) {
    if (msg.includes('already bootstrapped') || msg.includes('Input/output error')) {
      console.error('Agent likely already loaded; bootout first then retry.');
    }
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: install_launch_agent (called by run and ensure_supervisor_via_launchd) on macOS when launchctl bootstrap returns non-zero — e.g. "Bootstrap failed: 5: Input/output error" or "Operation already in progress" because the agent is already loaded.

Common situations: Re-running bootstrap when the agent is already loaded (launchctl requires bootout first); malformed or stale plist path; missing GUI domain (running in an SSH session without a user GUI domain); macOS sandbox/permission issues.

Related errors


AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01). Data as JSON: /api/errors/d4fcdb2317db94cb. Report an issue: GitHub.