astrid-runtime/astrid · error

capsule path is not valid UTF-8

Error message

capsule path is not valid UTF-8

What it means

`append_entry` requires the capsule-relative path to be valid UTF-8 so it can be written into the tar header. If the relative path contains bytes that are not valid UTF-8 (possible on Unix where paths are arbitrary bytes), `relative.to_str()` returns `None` and this error is raised. The library refuses rather than writing a tar entry with an ambiguous name.

Source

Thrown at crates/astrid-capsule-install/src/storage.rs:861

        let entry = entry.with_context(|| format!("read child of {}", path.display()))?;
        let name = entry.path();
        let metadata = fs::symlink_metadata(&name)
            .with_context(|| format!("inspect capsule source entry {}", name.display()))?;
        children.push((name, metadata));
    }
    children.sort_by(|left, right| left.0.cmp(&right.0));
    Ok(children)
}

fn append_entry(
    builder: &mut Builder<GzEncoder<Vec<u8>>>,
    root: &Path,
    relative: &Path,
    metadata: &Metadata,
) -> anyhow::Result<()> {
    let path = relative
        .to_str()
        .ok_or_else(|| anyhow::anyhow!("capsule path is not valid UTF-8"))?;
    if path.starts_with('/') || path.split('/').any(|part| part == ".." || part.is_empty()) {
        bail!("capsule path is not canonical: {path}");
    }
    let mut header = Header::new_gnu();
    header.set_uid(0);
    header.set_gid(0);
    header.set_mtime(0);
    header.set_mode(if metadata.is_dir() { 0o755 } else { 0o644 });
    if metadata.is_dir() {
        header.set_entry_type(EntryType::Directory);
        header.set_size(0);
        header.set_cksum();
        builder
            .append_data(&mut header, path, io::empty())
            .with_context(|| format!("append capsule directory {path}"))?;
    } else {
        let mut file =
            File::open(root.join(relative)).with_context(|| format!("open capsule file {path}"))?;

View on GitHub (pinned to affd8760f4)

Solutions

  1. Find and rename the offending file(s) to valid UTF-8 names, e.g. with `convmv -f latin1 -t utf8 -r <dir>` or `find <dir> | grep -Pv '^[\x00-\x7F\x80-\xF7]*$'` to locate them
  2. Recreate the capsule source from a clean checkout that only contains UTF-8 filenames
  3. If the tooling is under your control, validate entry names at intake time and reject/normalize non-UTF-8 names before archiving

Example fix

// before
$ ls my-capsule/src
caf???.rs   # Latin-1 encoded name

// after
$ convmv -f latin1 -t utf8 --notest -r my-capsule
canonical_capsule_archive(home, &capsule_root, ...)?;
Defensive patterns

Strategy: validation

Validate before calling

fn assert_all_names_utf8(root: &Path) -> anyhow::Result<()> {
    for entry in walkdir::WalkDir::new(root) {
        let entry = entry?;
        let rel = entry.path().strip_prefix(root)?;
        anyhow::ensure!(rel.to_str().is_some(),
            "non-UTF-8 path in capsule: {}", entry.path().display());
    }
    Ok(())
}
assert_all_names_utf8(&capsule_root)?;

Type guard

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

Try / catch

match canonical_capsule_archive(home, &root, ...) {
    Err(e) if e.to_string().contains("not valid UTF-8") => {
        // locate offending name and rename/normalize, then retry
    }
    Err(e) => return Err(e),
    Ok(a) => a,
}

Prevention

When it happens

Trigger: Calling `canonical_capsule_archive` over a source tree that contains a file or directory whose name includes non-UTF-8 bytes (e.g. Latin-1 encoded filenames from an old archive extraction, or filenames created by non-UTF-8 locale tools).

Common situations: Capsules packed on machines with non-UTF-8 filesystem locales; files unzipped from legacy ZIP archives with CP437/Latin-1 name encoding; files created with `touch $'\xff'` in scripts.

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