nikivdev/code · error

Failed to enable service: {}

Error message

Failed to enable service: {}

What it means

enable_service first bootstraps (or, for sudo services, shells out to sudo launchctl bootstrap) to load the launchd service; this error is raised when that first bootstrap command exits non-zero, with launchctl's stderr embedded in the message. It is the load step failing, distinct from the later bootstrap retry at error 685.

Source

Thrown at src/macos.rs:750

fn enable_service(svc: &LaunchdService) -> Result<()> {
    let domain = svc.service_type.domain();

    // First enable
    let target = format!("{}/{}", domain, svc.id);
    let mut cmd = if svc.service_type.requires_sudo() {
        let mut c = Command::new("sudo");
        c.args(["launchctl", "enable", &target]);
        c
    } else {
        let mut c = Command::new("launchctl");
        c.args(["enable", &target]);
        c
    };

    let output = cmd.output()?;
    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        bail!("Failed to enable service: {}", stderr);
    }

    // Then bootstrap (load)
    let mut cmd = if svc.service_type.requires_sudo() {
        let mut c = Command::new("sudo");
        c.args(["launchctl", "bootstrap", &domain]);
        c.arg(&svc.plist_path);
        c
    } else {
        let mut c = Command::new("launchctl");
        c.args(["bootstrap", &domain]);
        c.arg(&svc.plist_path);
        c
    };

    let output = cmd.output()?;
    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);

View on GitHub (pinned to a747e741ae)

Solutions

  1. Inspect the stderr embedded in the error for launchctl's exact reason.
  2. Run the enable command with sudo when the service type requires it.
  3. Validate the plist: `plutil -lint <path/to/plist>` and confirm the file exists.
  4. Bootstrap manually to debug: `sudo launchctl bootstrap gui/$(id -u) <plist>`.

Example fix

// before
flow macos enable my-daemon   // fails: Bootstrap failed: 5: Input/output error
// after
plutil -lint ~/Library/LaunchAgents/com.example.my-daemon.plist
sudo flow macos enable my-daemon
Defensive patterns

Strategy: validation

Validate before calling

let plist = format!("~/Library/LaunchAgents/com.example.{}.plist", label);
let ok = std::process::Command::new("plutil").args(["-lint", &plist]).status().map(|s| s.success()).unwrap_or(false);
if !ok { eprintln!("plist invalid or missing"); return; }

Type guard

fn is_bootstrap_failure(err: &anyhow::Error) -> bool {
    err.to_string().starts_with("Failed to enable service: ") || err.to_string().starts_with("Failed to bootstrap service: ")
}

Try / catch

match macos::run_enable(opts) {
    Err(e) if e.to_string().contains("Failed to enable service:") => {
        if e.to_string().contains("Operation not permitted") {
            // escalate: rerun with sudo
        } else {
            eprintln!("launchctl: {}", e);
        }
    }
    other => other?,
}

Prevention

When it happens

Trigger: Running enable_service for a service whose type requires sudo but is run without it, or launchctl bootstrap fails for reasons like a malformed plist, nonexistent plist path, or wrong domain target.

Common situations: Enabling a system service without sudo; typo in the plist path; plist with XML errors that launchctl rejects.

Related errors


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