{"record":{"id":"921ca826c889df78","repo":"astrid-runtime/astrid","slug":"sandbox-label-is-not-valid-utf-8","errorCode":null,"errorMessage":"sandbox {label} is not valid UTF-8: {}","messagePattern":"sandbox (.+?) is not valid UTF-8: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-workspace/src/sandbox/mod.rs","lineNumber":26,"sourceCode":"#[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): {}\",\n                path.display()\n            ),\n        ));\n    }\n    Ok(s)\n}\n\n/// A host-verified, read-only file the sandbox materializes inside a spawned\n/// child. `source` is the host-owned path the verified snapshot already lives","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-workspace/src/sandbox/mod.rs#L8-L44","documentation":"validate_sandbox_str requires the path to be valid UTF-8 because sandbox profiles are text formats. Non-UTF-8 paths (common on Unix, where paths are arbitrary bytes) cannot be safely interpolated, so the function rejects them with InvalidInput naming the label and the lossily-displayed path.","triggerScenarios":"Calling wrap_with_process_paths, validate_all_paths, or build_seatbelt_prefix with a Path built from raw bytes that are not valid UTF-8 (e.g. OsStr::from_bytes with latin-1 or mixed-encoding bytes).","commonSituations":"Files created with filenames in a legacy locale encoding; paths received over IPC or from archives with non-UTF-8 names; systems whose filesystem encoding differs from UTF-8.","solutions":["Rename the offending file/directory to a UTF-8 name","If the path came from OsString bytes, transcode to UTF-8 (or reject) before calling the sandbox API","Ensure the process locale/encoding producing the path emits UTF-8 (e.g. LC_ALL/LANG settings)","Reject non-UTF-8 paths at ingestion and report them to the user instead of passing them through"],"exampleFix":"// before\nlet p = PathBuf::from(std::ffi::OsString::from_vec(raw_bytes));\nwrap_with_process_paths(&ws, &[p], &[])?;\n// after\nlet s = std::str::from_utf8(&raw_bytes)?;\nlet p = PathBuf::from(s);\nwrap_with_process_paths(&ws, &[p], &[])?;","handlingStrategy":"validation","validationCode":"fn ensure_utf8(p: &Path) -> io::Result<()> { p.to_str().map(|_| ()).ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, format!(\"non-UTF-8 path: {}\", p.display()))) }","typeGuard":"fn is_utf8_path(p: &Path) -> bool { p.to_str().is_some() }","tryCatchPattern":"match validate_result { Err(e) if e.to_string().contains(\"not valid UTF-8\") => { /* rename/transcode the file or exclude it from the sandbox */ }, other => other, }","preventionTips":["Require UTF-8 filenames in your application (reject others at creation)","Set UTF-8 locales in environments that produce the paths","Transcode OsStr bytes to UTF-8 (or skip) before sandbox configuration"],"tags":["sandbox","path","utf-8","validation"],"backgroundTag":"invalid-argument-format","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"}