{"record":{"id":"8233668a38abd6f1","repo":"unicity-aos/aos-ce","slug":"embedded-capsule-has-no-name-migration","errorCode":null,"errorMessage":"embedded capsule has no name","messagePattern":"embedded capsule has no name","errorType":"validation","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/unicity-aos-bootstrap/src/migration.rs","lineNumber":475,"sourceCode":"        .map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))?;\n    let capsules = manifest\n        .get(\"capsule\")\n        .and_then(toml::Value::as_array)\n        .ok_or_else(|| {\n            io::Error::new(\n                io::ErrorKind::InvalidData,\n                \"embedded distro has no capsules\",\n            )\n        })?;\n    capsules\n        .iter()\n        .map(|capsule| {\n            capsule\n                .get(\"name\")\n                .and_then(toml::Value::as_str)\n                .map(str::to_owned)\n                .ok_or_else(|| {\n                    io::Error::new(io::ErrorKind::InvalidData, \"embedded capsule has no name\")\n                })\n        })\n        .collect()\n}\n\nfn archive_path(staging: &Path, relative: &Path, entries: &mut [Entry]) -> io::Result<()> {\n    if !is_safe_relative(relative) {\n        return invalid(\"imported activation path is unsafe\");\n    }\n    let archived = Path::new(IMPORT_ARCHIVE_DIR).join(relative);\n    let source = staging.join(relative);\n    let destination = staging.join(&archived);\n    if destination.exists() {\n        return invalid(\"imported activation archive contains a duplicate path\");\n    }\n    create_private_dir(destination.parent().expect(\"archive path has a parent\"))?;\n    fs::rename(&source, &destination)?;\n    sync_parent(&source)?;","sourceCodeStart":457,"sourceCodeEnd":493,"githubUrl":"https://github.com/unicity-aos/aos-ce/blob/f6f22024fb1e8d122f28a1b4a9f75aee448ae839/crates/unicity-aos-bootstrap/src/migration.rs#L457-L493","documentation":"unicity_ce_capsule_names maps over each entry of the manifest's `capsule` array and extracts its `name` string. If a capsule table has no `name` key (or it is not a string), this InvalidData io::Error is returned. It means one of the embedded distro's capsules is unnamed.","triggerScenarios":"Calling archive_inactive_activation_state when a `[[capsule]]` entry in the embedded distro manifest omits the `name` field, or defines `name` as a non-string (e.g. an integer or inline table).","commonSituations":"A hand-edited manifest where a capsule table was added without a name; a schema change where the field was renamed; a malformed build-generated manifest.","solutions":["Add a `name` string field to every `[[capsule]]` entry in the embedded distro manifest","Validate the manifest against the expected schema before embedding it in the distro","Rebuild the distro from an upstream manifest rather than editing the embedded copy by hand"],"exampleFix":"# before\n[[capsule]]\nversion = \"1.2.0\"\n\n# after\n[[capsule]]\nname = \"core\"\nversion = \"1.2.0\"","handlingStrategy":"validation","validationCode":"fn all_capsules_named(manifest: &str) -> bool {\n    toml::from_str::<toml::Value>(manifest).ok()\n        .and_then(|v| v.get(\"capsule\").and_then(|c| c.as_array()).cloned())\n        .map(|caps| caps.iter().all(|c| c.get(\"name\").and_then(|n| n.as_str()).map(|s| !s.is_empty()).unwrap_or(false)))\n        .unwrap_or(false)\n}","typeGuard":"fn capsule_name(capsule: &toml::Value) -> Option<&str> {\n    capsule.get(\"name\").and_then(|n| n.as_str())\n}","tryCatchPattern":"match unicity_ce_capsule_names() {\n    Ok(names) => proceed(names),\n    Err(e) if e.to_string().contains(\"embedded capsule has no name\") =>\n        eprintln!(\"a [[capsule]] entry is missing its name field\"),\n    Err(e) => return Err(e),\n}","preventionTips":["Add a lint/CI step asserting each [[capsule]] has a non-empty string name","Use a typed manifest struct with a required name field instead of raw toml::Value lookups","Validate manifests against a JSON/TOML schema before embedding"],"tags":["rust","toml","config","migration"],"backgroundTag":"missing-required-config-field","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"}