astrid-runtime/astrid · error

sandbox {label} is not valid UTF-8: {}

Error message

sandbox {label} is not valid UTF-8: {}

What it means

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.

Source

Thrown at crates/astrid-workspace/src/sandbox/mod.rs:26

#[cfg(target_os = "macos")]
mod seatbelt;

/// Validate a path for safe interpolation into sandbox profiles (SBPL/bwrap).
///
/// Rejects relative paths, non-UTF-8, double-quote, backslash, and null byte -
/// all of which can break or bypass sandbox profile syntax.
fn validate_sandbox_str<'a>(path: &'a Path, label: &str) -> io::Result<&'a str> {
    if !path.is_absolute() {
        return Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            format!(
                "sandbox {label} must be an absolute path, got: {}",
                path.display()
            ),
        ));
    }
    let s = path.to_str().ok_or_else(|| {
        io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("sandbox {label} is not valid UTF-8: {}", path.display()),
        )
    })?;
    if s.contains(['"', '\\', '\0']) {
        return Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            format!(
                "sandbox {label} contains forbidden characters (double-quote, backslash, or null): {}",
                path.display()
            ),
        ));
    }
    Ok(s)
}

/// A host-verified, read-only file the sandbox materializes inside a spawned
/// child. `source` is the host-owned path the verified snapshot already lives

View on GitHub (pinned to affd8760f4)

Solutions

  1. Rename the offending file/directory to a UTF-8 name
  2. If the path came from OsString bytes, transcode to UTF-8 (or reject) before calling the sandbox API
  3. Ensure the process locale/encoding producing the path emits UTF-8 (e.g. LC_ALL/LANG settings)
  4. Reject non-UTF-8 paths at ingestion and report them to the user instead of passing them through

Example fix

// before
let p = PathBuf::from(std::ffi::OsString::from_vec(raw_bytes));
wrap_with_process_paths(&ws, &[p], &[])?;
// after
let s = std::str::from_utf8(&raw_bytes)?;
let p = PathBuf::from(s);
wrap_with_process_paths(&ws, &[p], &[])?;
Defensive patterns

Strategy: validation

Validate before calling

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()))) }

Type guard

fn is_utf8_path(p: &Path) -> bool { p.to_str().is_some() }

Try / catch

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, }

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/921ca826c889df78. Report an issue: GitHub.