astrid-runtime/astrid · error

capsule projection path is not UTF-8: {}

Error message

capsule projection path is not UTF-8: {}

What it means

Thrown when a path inside the capsule projection cannot be converted to a UTF-8 string via `Path::to_str`. The inventory requires relative path text (for hashing/registration), so non-UTF-8 filenames are rejected explicitly.

Source

Thrown at crates/astrid-kernel/src/lib.rs:1633

    /// Inventory a projection without traversing redirects or special files.
    #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
    fn inventory_projection_files(root: &Path) -> anyhow::Result<ProjectionInventory> {
        fn walk(
            root: &Path,
            directory: &Path,
            inventory: &mut ProjectionInventory,
        ) -> anyhow::Result<()> {
            for entry in std::fs::read_dir(directory).map_err(|error| {
                anyhow::anyhow!("read capsule projection {}: {error}", directory.display())
            })? {
                let entry = entry
                    .map_err(|error| anyhow::anyhow!("read capsule projection entry: {error}"))?;
                let path = entry.path();
                let relative = path.strip_prefix(root).map_err(|_| {
                    anyhow::anyhow!("capsule projection escaped its root: {}", path.display())
                })?;
                let relative_text = relative.to_str().ok_or_else(|| {
                    anyhow::anyhow!("capsule projection path is not UTF-8: {}", path.display())
                })?;
                let metadata = std::fs::symlink_metadata(&path).map_err(|error| {
                    anyhow::anyhow!("inspect capsule projection {}: {error}", path.display())
                })?;
                let file_type = metadata.file_type();
                if file_type.is_symlink() {
                    anyhow::bail!(
                        "capsule projection contains a symbolic link: {}",
                        path.display()
                    );
                }
                if file_type.is_dir() {
                    inventory.directories.insert(relative_text.to_owned());
                    walk(root, &path, inventory)?;
                } else if file_type.is_file() {
                    inventory.files.insert(relative_text.to_owned());
                } else {
                    anyhow::bail!(

View on GitHub (pinned to affd8760f4)

Solutions

  1. Rebuild the capsule with UTF-8-only filenames.
  2. Sanitize/normalize filenames at capsule build time to enforce UTF-8.
  3. Locate the offending path (printed in the error) and rename or remove it.
  4. If the name is correct but encoded differently, transcode it to UTF-8 before projecting.
Defensive patterns

Strategy: validation

Validate before calling

fn all_paths_utf8(dir: &Path) -> anyhow::Result<()> {
    for entry in std::fs::read_dir(dir)? {
        let p = entry?.path();
    anyhow::ensure!(p.to_str().is_some(), "non-UTF-8 path: {}", p.display());
        if p.is_dir() { all_paths_utf8(&p)?; }
    }
    Ok(())
}

Type guard

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

Prevention

When it happens

Trigger: A file or directory inside the projection has a name that is not valid UTF-8 (raw bytes from a tarball, legacy encoding, or attacker-controlled names).

Common situations: Extracting archives built on systems with non-UTF-8 filenames (e.g. Latin-1) into the projection; macOS NFD vs NFC issues do not trigger this, but raw-byte names do.

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/4fbc4bf451cbb5d6. Report an issue: GitHub.