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
- 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
- Drive selection through probe() and treat ErrorKind::NotFound as "backend unavailable" — fall through to the next backend
- Gate seatbelt usage with `#[cfg(target_os = "macos")]` so non-macOS builds never construct it
- 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
- Probe seatbelt only in macOS-gated code paths (#[cfg(target_os = "macos")])
- Use probe() during auto-detection and skip on NotFound instead of propagating
- Ensure $TMPDIR is writable so the later policy-file write under zeroclaw-seatbelt cannot fail after the binary check
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
- WASM runtime does not support shell commands. Use `execute_m
- No credentials found for user '{user_id}'
- the launchd daemon runner is only supported on macOS
- SOP not found: {n}
- Landlock is only supported on Linux with the sandbox-landloc
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/075e3353f1637f67.
Report an issue: GitHub.