{"record":{"id":"02fd83a0d4d28edf","repo":"unicity-aos/aos-ce","slug":"embedded-capsule-source-has-no-asset","errorCode":null,"errorMessage":"embedded capsule source has no asset","messagePattern":"embedded capsule source has no asset","errorType":"validation","errorClass":"io::Error","httpStatus":null,"severity":"critical","filePath":"crates/unicity-aos-bootstrap/src/lib.rs","lineNumber":792,"sourceCode":"        .map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))?;\n    let capsules = manifest\n        .get_mut(\"capsule\")\n        .and_then(toml::Value::as_array_mut)\n        .ok_or_else(|| {\n            io::Error::new(\n                io::ErrorKind::InvalidData,\n                \"embedded distro has no capsules\",\n            )\n        })?;\n    for capsule in capsules {\n        let source = capsule\n            .get(\"source\")\n            .and_then(toml::Value::as_str)\n            .ok_or_else(|| {\n                io::Error::new(io::ErrorKind::InvalidData, \"embedded capsule has no source\")\n            })?;\n        let asset = Path::new(source).file_name().ok_or_else(|| {\n            io::Error::new(\n                io::ErrorKind::InvalidData,\n                \"embedded capsule source has no asset\",\n            )\n        })?;\n        let absolute = capsule_dir.join(asset);\n        let absolute = absolute.to_str().ok_or_else(|| {\n            io::Error::new(\n                io::ErrorKind::InvalidInput,\n                \"AOS capsule directory must be valid UTF-8 for the TOML manifest\",\n            )\n        })?;\n        capsule[\"source\"] = toml::Value::String(absolute.to_owned());\n    }\n    toml::to_string_pretty(&manifest)\n        .map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))\n}\n\n#[cfg(test)]","sourceCodeStart":774,"sourceCodeEnd":810,"githubUrl":"https://github.com/unicity-aos/aos-ce/blob/f6f22024fb1e8d122f28a1b4a9f75aee448ae839/crates/unicity-aos-bootstrap/src/lib.rs#L774-L810","documentation":"Thrown by materialize_manifest when a capsule entry's `source` string has no final path component — i.e. Path::file_name() returns None. This happens for sources ending in `..`, `/`, or empty/root-like paths, so the library cannot derive the asset filename to join with the capsule directory.","triggerScenarios":"An embedded manifest entry with source=\"capsules/\", source=\"\", source=\"..\", or a path terminating in a parent/curdir component; materialize_manifest cannot extract an asset name and fails during ensure_unicity_ce_manifest.","commonSituations":"Template/variable substitution in the manifest producing a directory path or empty string; hand-edited source values with a trailing slash; scripts generating sources programmatically and omitting the filename.","solutions":["Set source to a full relative file path ending in the .capsule filename, e.g. \"capsules/kernel-core.capsule\"","Remove trailing slashes, empty values, or `..` components from source","Regenerate the manifest programmatically to guarantee each source ends with a concrete filename"],"exampleFix":"// before\nsource = \"capsules/\"\n// after\nsource = \"capsules/kernel-core.capsule\"","handlingStrategy":"validation","validationCode":"fn source_has_asset(source: &str) -> bool {\n    std::path::Path::new(source).file_name().is_some()\n}","typeGuard":"fn has_file_name(source: &str) -> bool {\n    !source.is_empty()\n        && std::path::Path::new(source).file_name()\n            .map(|f| f != \"..\" && f != \".\")\n            .unwrap_or(false)\n}","tryCatchPattern":"match bootstrap::ensure_unicity_ce_manifest(&home) {\n    Err(e) if e.to_string().contains(\"has no asset\") => {\n        eprintln!(\"A capsule `source` must be a file path with a filename: {e}\");\n    }\n    Err(e) => return Err(e),\n    Ok(manifest) => manifest,\n}","preventionTips":["Always write source as a relative file path ending in the .capsule filename","Reject trailing slashes, empty strings, and `..` components when generating sources","Validate sources with Path::file_name() before shipping the manifest"],"tags":["rust","manifest","toml","path","capsules"],"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"}