zeroclaw-labs/zeroclaw · error · anyhow::Error

the launchd daemon runner is only supported on macOS

Error message

the launchd daemon runner is only supported on macOS

What it means

run_launchd_daemon is compiled as a stub on non-macOS targets that always bails (service/mod.rs:333-338). The launchd daemon runner captures launchd-managed stdout/stderr paths, so calling it on Linux or Windows can never succeed.

Source

Thrown at crates/zeroclaw-runtime/src/service/mod.rs:336

{
    let mut buffer = vec![0; 16 * 1024];
    loop {
        match pipe.read(&mut buffer).await {
            Ok(0) => break,
            Ok(read) => sink.push(buffer[..read].to_vec()),
            Err(error) => {
                sink.push(format!("launchd log pipe read failed: {error}\n").into_bytes());
                break;
            }
        }
    }
}

pub async fn run_launchd_daemon(config_dir: &Path) -> Result<()> {
    #[cfg(not(target_os = "macos"))]
    {
        let _ = config_dir;
        bail!("the launchd daemon runner is only supported on macOS")
    }

    #[cfg(target_os = "macos")]
    {
        let paths = launchd_capture_paths(config_dir);
        run_with_launchd_capture(paths, || {
            let executable = std::env::current_exe()
                .context("Failed to resolve the launchd daemon executable")?;
            let mut command = TokioCommand::new(executable);
            command.arg("--config-dir").arg(config_dir).arg("daemon");
            Ok(command)
        })
        .await
    }
}

#[cfg(any(target_os = "macos", test))]
async fn run_with_launchd_capture<F>(paths: LaunchdCapturePaths, make_command: F) -> Result<()>

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Gate the call: invoke run_launchd_daemon only when std::env::consts::OS == "macos" (or via #[cfg(target_os = "macos")])
  2. On Linux use the OpenRC runner (run_openrc_log_writer) or the platform-appropriate service path
  3. Derive the runner choice from the detected OS in your dispatcher

Example fix

// before
run_launchd_daemon(config_dir).await?;

// after
#[cfg(target_os = "macos")]
run_launchd_daemon(config_dir).await?;
#[cfg(not(target_os = "macos"))]
anyhow::bail!("launchd runner requires macOS; this build targets {}", std::env::consts::OS);
Defensive patterns

Strategy: validation

Validate before calling

fn is_macos() -> bool {
    std::env::consts::OS == "macos"
}

if is_macos() {
    run_launchd_daemon(config_dir).await?;
} else {
    tracing::warn!(os = std::env::consts::OS, "skipping launchd daemon: macOS only");
}

Type guard

fn supports_launchd() -> bool { cfg!(target_os = "macos") }

Try / catch

If the call still fails, treat 'only supported on macOS' as a dispatcher bug: log the detected OS and route to the OpenRC or platform runner; never retry the launchd path on a non-macOS host.

Prevention

When it happens

Trigger: Invoking the launchd daemon entry point on a Linux or Windows build — e.g. a service dispatcher keyed by config instead of OS, or a Linux CI host running macOS-targeted service commands.

Common situations: A macos-style service config deployed to a Linux box; cross-platform binary with a single hardcoded runner; CI matrix running the launchd path on the wrong OS job.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/bb75f40920f6f3a1. Report an issue: GitHub.