{"record":{"id":"ea2d4c9e7f016e80","repo":"unicity-aos/aos-ce","slug":"capsule-asset-is-not-utf-8","errorCode":null,"errorMessage":"capsule asset is not UTF-8","messagePattern":"capsule asset is not UTF-8","errorType":"validation","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/unicity-aos-bootstrap/src/lib.rs","lineNumber":694,"sourceCode":"                .and_then(|component| match component {\n                    std::path::Component::Normal(name) => Some(name),\n                    _ => None,\n                })\n                .is_none()\n            || components.next().is_some()\n            || relative.extension() != Some(OsStr::new(\"capsule\"))\n        {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                format!(\"embedded capsule source is not canonical: {source}\"),\n            ));\n        }\n        let asset = relative\n            .file_name()\n            .expect(\"validated capsule source has a filename\")\n            .to_str()\n            .ok_or_else(|| {\n                io::Error::new(io::ErrorKind::InvalidData, \"capsule asset is not UTF-8\")\n            })?\n            .to_owned();\n        if asset != format!(\"{package}.capsule\") {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                format!(\"embedded capsule source does not match package {package}\"),\n            ));\n        }\n        if assets.contains(&asset) {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                format!(\"embedded distro selects duplicate capsule asset {asset}\"),\n            ));\n        }\n        assets.push(asset);\n    }\n    Ok(assets)\n}","sourceCodeStart":676,"sourceCodeEnd":712,"githubUrl":"https://github.com/unicity-aos/aos-ce/blob/f6f22024fb1e8d122f28a1b4a9f75aee448ae839/crates/unicity-aos-bootstrap/src/lib.rs#L676-L712","documentation":"After path validation, the library converts the capsule asset's filename to a Rust str to use as an embedded asset key. This error is thrown when that filename is not valid UTF-8 (Rust OsStr/Path are not guaranteed UTF-8). Practically it means the capsule file on disk has a non-UTF-8 name, which cannot be used as an embedded asset identifier.","triggerScenarios":"A `[[capsule]]` source resolving to a filename containing raw non-UTF-8 bytes (e.g. Latin-1 encoded characters or invalid byte sequences created on some filesystems), passed through capsule_assets_from_manifest via capsule_dir_with, prepare_unicity_ce_init, or install_capsule_fixtures.","commonSituations":"A capsule file renamed on a filesystem with a non-UTF-8 locale/encoding; a script writing filenames from unvalidated bytes; files transferred from systems using legacy codepages; accidental binary corruption of a filename.","solutions":["Rename the capsule file so its name is valid UTF-8, ideally plain ASCII matching `<package>.capsule`.","Regenerate the capsule file with build tooling that uses ASCII identifiers for package names.","Check that the manifest's source string itself is clean UTF-8 TOML (a valid TOML string already is; the corruption is typically on the filesystem side or from escaped bytes).","Audit manifest generation scripts for byte-level filename handling (e.g. shelling out with raw locale-dependent output)."],"exampleFix":"// before (filename with non-UTF-8 bytes)\n$ mv capsules/foo.capsule $'capsules/fo\\xffo.capsule'\n\n// after\n$ mv capsules/foo.capsule capsules/foo.capsule   # plain ASCII, matches package name \"foo\"","handlingStrategy":"validation","validationCode":"// Rust: verify asset filenames are valid UTF-8 before invoking the API\nfn ensure_utf8_asset_names(manifest_toml: &str) -> Result<(), String> {\n    let v: toml::Value = toml::from_str(manifest_toml).map_err(|e| e.to_string())?;\n    for c in v.get(\"capsule\").and_then(toml::Value::as_array).unwrap_or(&vec![]) {\n        if let Some(src) = c.get(\"source\").and_then(toml::Value::as_str) {\n            let name = std::path::Path::new(src).file_name().unwrap_or_default();\n            if name.to_str().is_none() {\n                return Err(format!(\"asset filename for {src} is not UTF-8\"));\n            }\n        }\n    }\n    Ok(())\n}","typeGuard":"fn is_utf8_file_name(src: &str) -> bool {\n    std::path::Path::new(src).file_name().map(|n| n.to_str().is_some()).unwrap_or(false)\n}","tryCatchPattern":"match capsule_assets_from_manifest() {\n    Err(e) if e.to_string().contains(\"capsule asset is not UTF-8\") => {\n        eprintln!(\"{e}; rename the capsule file to a UTF-8 (ASCII) name matching <package>.capsule\");\n    }\n    other => other,\n}","preventionTips":["Build capsule files with ASCII-only package identifiers so filenames are always valid UTF-8.","Avoid renaming capsule files with shell scripts under non-UTF-8 locales; set LC_ALL=C.UTF-8 in build environments.","Validate filenames (e.g. reject non-ASCII bytes) when ingesting capsule artifacts from external systems."],"tags":["encoding","utf-8","filesystem","capsule"],"backgroundTag":"invalid-argument-format","analyzedSha":"f6f22024fb1e8d122f28a1b4a9f75aee448ae839","analyzedAt":"2026-09-13T03:04:44.565Z","contentChangedAt":"2026-09-13T03:04:44.565Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}