zeroclaw-labs/zeroclaw · error · std::io::Error

sandbox-exec not found (requires macOS)

Error message

sandbox-exec not found (requires macOS)

What it means

SeatbeltSandbox::with_workspace first calls is_installed(), which is literally `Path::new("/usr/bin/sandbox-exec").is_file()` (seatbelt.rs:7,60-62); when that fixed path is absent it returns io::ErrorKind::NotFound with this message. sandbox-exec is Apple's Seatbelt policy tool that the backend shells out to, so the error means "this machine is not a macOS host with sandbox-exec" — it has nothing to do with the workspace argument. Construction proceeds to write a per-session .sb policy under $TMPDIR/zeroclaw-seatbelt only after this binary check passes.

Source

Thrown at crates/zeroclaw-runtime/src/security/seatbelt.rs:30

    policy_dir: PathBuf,
    /// Path to the generated policy file for this session.
    policy_path: PathBuf,
}

impl SeatbeltSandbox {
    /// Create a new Seatbelt sandbox, generating a per-session policy file.
    /// Returns an error if `sandbox-exec` is not available or the policy file
    /// cannot be written.
    pub fn new() -> std::io::Result<Self> {
        Self::with_workspace(None)
    }

    /// Create a new Seatbelt sandbox for the provided workspace root.
    /// If no workspace is provided, falls back to the process current
    /// directory for compatibility with direct construction.
    pub fn with_workspace(workspace: Option<&Path>) -> std::io::Result<Self> {
        if !Self::is_installed() {
            return Err(std::io::Error::new(
                std::io::ErrorKind::NotFound,
                "sandbox-exec not found (requires macOS)",
            ));
        }

        let policy_dir = std::env::temp_dir().join("zeroclaw-seatbelt");
        std::fs::create_dir_all(&policy_dir)?;

        let session_id = uuid::Uuid::new_v4();
        let policy_path = policy_dir.join(format!("{session_id}.sb"));

        let workspace = workspace
            .map(Path::to_path_buf)
            .unwrap_or_else(|| std::env::current_dir().unwrap_or_else(|_| PathBuf::from("/tmp")));
        let policy = generate_policy(&workspace);
        std::fs::write(&policy_path, &policy)?;

        Ok(Self {

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Confirm the platform and binary: `ls -l /usr/bin/sandbox-exec` on a stock macOS host; on Linux use LandlockSandbox (with the sandbox-landlock feature) instead
  2. Drive selection through probe() and treat ErrorKind::NotFound as "backend unavailable" — fall through to the next backend
  3. Gate seatbelt usage with `#[cfg(target_os = "macos")]` so non-macOS builds never construct it
  4. If a custom macOS image dropped the binary, restore it or deploy on a stock macOS host

Example fix

// before
let sandbox = SeatbeltSandbox::with_workspace(Some(&workspace))?; // Err(NotFound) off macOS

// after — probe first, fall back to the platform-appropriate backend
let sandbox = match SeatbeltSandbox::probe() {
    Ok(s) => s,
    Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
        LandlockSandbox::with_workspace(Some(workspace))? // Linux path (needs sandbox-landlock)
    }
    Err(e) => return Err(e.into()),
};
Defensive patterns

Strategy: validation

Validate before calling

// mirrors SeatbeltSandbox::is_installed()
fn seatbelt_installed() -> bool {
    std::path::Path::new("/usr/bin/sandbox-exec").is_file()
}

Type guard

fn is_not_found(e: &std::io::Error) -> bool {
    e.kind() == std::io::ErrorKind::NotFound
}

Try / catch

match SeatbeltSandbox::with_workspace(Some(&ws)) {
    Ok(s) => s,
    Err(e) if e.kind() == std::io::ErrorKind::NotFound => { /* not macOS: next backend */ }
    Err(e) => return Err(e.into()), // e.g. policy-file write failure
}

Prevention

When it happens

Trigger: Constructing SeatbeltSandbox via new(), with_workspace(Some(..)), or probe() on Linux/Windows, in containers, or on any macOS image where /usr/bin/sandbox-exec is missing; auto-detection loops that probe Seatbelt on non-Mac hosts hit it as a routine skip signal.

Common situations: Linux CI runners; dev boxes on Linux testing macOS-only code paths; Docker containers (even on macOS hosts, the container filesystem lacks host binaries); hardened or minimal macOS images where the tool was removed (Apple has it deprecated).

Related errors


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