{"record":{"id":"80784c65950318e5","repo":"astrid-runtime/astrid","slug":"sandbox-label-must-be-an-absolute-path-got","errorCode":null,"errorMessage":"sandbox {label} must be an absolute path, got: {}","messagePattern":"sandbox (.+?) must be an absolute path, got: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-workspace/src/sandbox/mod.rs","lineNumber":17,"sourceCode":"use std::ffi::OsString;\nuse std::io;\nuse std::path::{Path, PathBuf};\nuse std::process::Command;\n\n#[cfg(target_os = \"linux\")]\nmod bwrap;\n#[cfg(target_os = \"macos\")]\nmod seatbelt;\n\n/// Validate a path for safe interpolation into sandbox profiles (SBPL/bwrap).\n///\n/// Rejects relative paths, non-UTF-8, double-quote, backslash, and null byte -\n/// all of which can break or bypass sandbox profile syntax.\nfn validate_sandbox_str<'a>(path: &'a Path, label: &str) -> io::Result<&'a str> {\n    if !path.is_absolute() {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidInput,\n            format!(\n                \"sandbox {label} must be an absolute path, got: {}\",\n                path.display()\n            ),\n        ));\n    }\n    let s = path.to_str().ok_or_else(|| {\n        io::Error::new(\n            io::ErrorKind::InvalidInput,\n            format!(\"sandbox {label} is not valid UTF-8: {}\", path.display()),\n        )\n    })?;\n    if s.contains(['\"', '\\\\', '\\0']) {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidInput,\n            format!(\n                \"sandbox {label} contains forbidden characters (double-quote, backslash, or null): {}\",","sourceCodeStart":1,"sourceCodeEnd":35,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-workspace/src/sandbox/mod.rs#L1-L35","documentation":"validate_sandbox_str checks paths interpolated into sandbox profiles (SBPL/bwrap). A relative path cannot be safely or meaningfully expressed in the profile, so the function rejects it with InvalidInput naming the label (e.g. 'process read path') and the offending path.","triggerScenarios":"Calling wrap_with_process_paths with relative extra_read_paths/extra_write_paths/injection paths, validate_all_paths with relative workspace paths, or build_seatbelt_prefix with a relative path.","commonSituations":"Users passing CLI-relative paths like './data' or bare 'data' instead of absolute ones; config files with relative paths resolved against the wrong CWD; env vars holding relative paths.","solutions":["Convert the path to absolute with std::fs::canonicalize (or path.absolutize) before calling the sandbox API","Use fs::canonicalize to also resolve symlinks, then pass the canonical path","If the path may not exist yet, anchor it explicitly: PathBuf::from(\"/\").join(relative) or join against a known root","Fix configuration files or env vars to store absolute paths"],"exampleFix":"// before\nwrap_with_process_paths(&ws, &[PathBuf::from(\"./logs\")], &[])?;\n// after\nlet abs = std::fs::canonicalize(\"./logs\")?;\nwrap_with_process_paths(&ws, &[abs], &[])?;","handlingStrategy":"validation","validationCode":"fn ensure_absolute(p: &Path) -> io::Result<()> { if !p.is_absolute() { Err(io::Error::new(io::ErrorKind::InvalidInput, format!(\"path must be absolute: {}\", p.display()))) } else { Ok(()) } }","typeGuard":"fn is_abs(p: &Path) -> bool { p.is_absolute() }","tryCatchPattern":"match wrap_with_process_paths(&ws, &paths, &[]) { Err(e) if e.kind() == io::ErrorKind::InvalidInput && e.to_string().contains(\"must be an absolute path\") => { /* canonicalize and retry or report to user */ }, other => other, }","preventionTips":["Always fs::canonicalize user/config-supplied paths before passing them","Store absolute paths in configuration files","Anchor relative paths against an explicit known root, never the CWD"],"tags":["sandbox","path","validation","invalid-input"],"backgroundTag":"invalid-argument-value","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}