{"record":{"id":"bf44441b33a7d345","repo":"astrid-runtime/astrid","slug":"capsule-path-is-not-valid-utf-8","errorCode":null,"errorMessage":"capsule path is not valid UTF-8","messagePattern":"capsule path is not valid UTF-8","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-capsule-install/src/storage.rs","lineNumber":861,"sourceCode":"        let entry = entry.with_context(|| format!(\"read child of {}\", path.display()))?;\n        let name = entry.path();\n        let metadata = fs::symlink_metadata(&name)\n            .with_context(|| format!(\"inspect capsule source entry {}\", name.display()))?;\n        children.push((name, metadata));\n    }\n    children.sort_by(|left, right| left.0.cmp(&right.0));\n    Ok(children)\n}\n\nfn append_entry(\n    builder: &mut Builder<GzEncoder<Vec<u8>>>,\n    root: &Path,\n    relative: &Path,\n    metadata: &Metadata,\n) -> anyhow::Result<()> {\n    let path = relative\n        .to_str()\n        .ok_or_else(|| anyhow::anyhow!(\"capsule path is not valid UTF-8\"))?;\n    if path.starts_with('/') || path.split('/').any(|part| part == \"..\" || part.is_empty()) {\n        bail!(\"capsule path is not canonical: {path}\");\n    }\n    let mut header = Header::new_gnu();\n    header.set_uid(0);\n    header.set_gid(0);\n    header.set_mtime(0);\n    header.set_mode(if metadata.is_dir() { 0o755 } else { 0o644 });\n    if metadata.is_dir() {\n        header.set_entry_type(EntryType::Directory);\n        header.set_size(0);\n        header.set_cksum();\n        builder\n            .append_data(&mut header, path, io::empty())\n            .with_context(|| format!(\"append capsule directory {path}\"))?;\n    } else {\n        let mut file =\n            File::open(root.join(relative)).with_context(|| format!(\"open capsule file {path}\"))?;","sourceCodeStart":843,"sourceCodeEnd":879,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-capsule-install/src/storage.rs#L843-L879","documentation":"`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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["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","Recreate the capsule source from a clean checkout that only contains UTF-8 filenames","If the tooling is under your control, validate entry names at intake time and reject/normalize non-UTF-8 names before archiving"],"exampleFix":"// before\n$ ls my-capsule/src\ncaf???.rs   # Latin-1 encoded name\n\n// after\n$ convmv -f latin1 -t utf8 --notest -r my-capsule\ncanonical_capsule_archive(home, &capsule_root, ...)?;","handlingStrategy":"validation","validationCode":"fn assert_all_names_utf8(root: &Path) -> anyhow::Result<()> {\n    for entry in walkdir::WalkDir::new(root) {\n        let entry = entry?;\n        let rel = entry.path().strip_prefix(root)?;\n        anyhow::ensure!(rel.to_str().is_some(),\n            \"non-UTF-8 path in capsule: {}\", entry.path().display());\n    }\n    Ok(())\n}\nassert_all_names_utf8(&capsule_root)?;","typeGuard":"fn is_utf8_path(p: &Path) -> bool { p.to_str().is_some() }","tryCatchPattern":"match canonical_capsule_archive(home, &root, ...) {\n    Err(e) if e.to_string().contains(\"not valid UTF-8\") => {\n        // locate offending name and rename/normalize, then retry\n    }\n    Err(e) => return Err(e),\n    Ok(a) => a,\n}","preventionTips":["Run under a UTF-8 locale (LC_ALL=C.UTF-8) when generating capsule files","Normalize filenames at intake: reject or transcode non-UTF-8 names when ingesting user archives","Use convmv or similar to normalize legacy-encoded trees before packing","Add a pre-archive lint that walks the tree and asserts Path::to_str().is_some() for every entry"],"tags":["filesystem","utf-8","encoding","rust","archive"],"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"}