{"record":{"id":"6709b318e964f897","repo":"astrid-runtime/astrid","slug":"durable-capsule-archive-path-is-not-utf-8","errorCode":null,"errorMessage":"durable capsule archive path is not UTF-8","messagePattern":"durable capsule archive path is not UTF-8","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-capsule-install/src/storage.rs","lineNumber":382,"sourceCode":"        if path.is_absolute()\n            || path.components().any(|component| {\n                matches!(\n                    component,\n                    std::path::Component::ParentDir | std::path::Component::RootDir\n                )\n            })\n        {\n            bail!(\"durable capsule archive contains unsafe path\");\n        }\n\n        let entry_type = entry.header().entry_type();\n        if !entry_type.is_dir() && !entry_type.is_file() {\n            bail!(\"durable capsule archive contains a link or special file\");\n        }\n\n        let name = path\n            .to_str()\n            .ok_or_else(|| anyhow::anyhow!(\"durable capsule archive path is not UTF-8\"))?\n            .replace('\\\\', \"/\");\n        if files.contains_key(&name) || directories.contains(&name) {\n            bail!(\"durable capsule archive contains duplicate path {name}\");\n        }\n        if entry_type.is_dir() {\n            if !directories.insert(name) {\n                bail!(\"durable capsule archive contains duplicate directory path\");\n            }\n            continue;\n        }\n\n        let mut bytes = Vec::new();\n        entry\n            .read_to_end(&mut bytes)\n            .with_context(|| format!(\"read durable capsule archive file {name}\"))?;\n        files.insert(name, bytes);\n    }\n    Ok(ArchiveInventory { files, directories })","sourceCodeStart":364,"sourceCodeEnd":400,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-capsule-install/src/storage.rs#L364-L400","documentation":"read_archive_files enumerates every entry in a durable capsule archive and requires each member path to be valid UTF-8 so names can be normalized ('\\' -> '/') and checked for duplicates across files and directories. An entry whose path is not valid UTF-8 aborts the whole read with this error.","triggerScenarios":"read_verified_durable_package_for_owner (and the cross-binding mismatch test path) processes a durable archive containing an entry with raw non-UTF-8 path bytes — typically archives produced on non-UTF-8 filesystems or by legacy packing tools.","commonSituations":"Durable packages built on hosts with legacy locale settings; archives extracted from external sources and republished without path sanitization; Windows-created archives with codepage-encoded names.","solutions":["Inspect archive entry names to locate the non-UTF-8 path and rename it before republishing.","Rebuild the durable package with a UTF-8 locale so tar records UTF-8 names.","Run convmv on the source tree to convert filenames to UTF-8, then republish the capsule.","Verify the published capsule with the verification path (read_verified_durable_package) after republishing."],"exampleFix":"// before\nconvmv --notest -r ./src  # skipping conversion leaves non-UTF-8 names\n// after\nconvmv -f latin1 -t utf8 -r --notest ./src && capsule publish ./src","handlingStrategy":"validation","validationCode":"fn durable_paths_utf8(tar_path: &std::path::Path) -> anyhow::Result<()> {\n    let f = std::fs::File::open(tar_path)?;\n    let mut tar = tar::Archive::new(std::io::BufReader::new(f));\n    for entry in tar.entries()? {\n        let p = entry?.path()?.to_path_buf();\n        if p.to_str().is_none() {\n            anyhow::bail!(\"durable archive has non-UTF-8 path: {}\", p.display());\n        }\n    }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Publish durable packages only from UTF-8 filesystems/locales.","Sanitize source-tree filenames (convmv) before publishing.","Run read_verified_durable_package after publishing to catch format issues early."],"tags":["archive","utf-8","storage"],"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-17T15:17:12.973Z"}