unicity-aos/aos-ce · error · std::io::Error
embedded capsule has no name
Error message
embedded capsule has no name
What it means
After locating the `capsule` array, capsule_assets_from_manifest iterates each capsule table and reads its `name` field as a string. This error is thrown when a `[[capsule]]` entry is missing the `name` key or the value is not a string. The name is required because the asset filename must equal `<name>.capsule`.
Solutions
- Add a string `name` field to the offending `[[capsule]]` entry matching the capsule's package name.
- Ensure `name` is a plain TOML string, not a number or other type (quote it if needed).
- Check the entry immediately before/after in the array — the error does not identify which entry failed, so validate each `[[capsule]]` block.
- Regenerate the manifest with tooling that guarantees both `name` and `source` are present per entry.
Example fix
// before [[capsule]] source = "capsules/foo.capsule" // after [[capsule]] name = "foo" source = "capsules/foo.capsule"
Defensive patterns
Strategy: validation
Validate before calling
// Rust: check every capsule entry has a string name before calling the API
fn ensure_capsules_named(manifest_toml: &str) -> Result<(), String> {
let v: toml::Value = toml::from_str(manifest_toml).map_err(|e| e.to_string())?;
for (i, c) in v.get("capsule").and_then(toml::Value::as_array).unwrap_or(&vec![]).iter().enumerate() {
if c.get("name").and_then(toml::Value::as_str).map(str::is_empty) != Some(false) {
return Err(format!("capsule entry #{i} is missing a non-empty string `name`"));
}
}
Ok(())
} Type guard
fn capsule_name(capsule: &toml::Value) -> Option<&str> {
capsule.get("name").and_then(toml::Value::as_str).filter(|s| !s.is_empty())
} Try / catch
match capsule_assets_from_manifest() {
Err(e) if e.to_string().contains("embedded capsule has no name") => {
eprintln!("a [[capsule]] entry in the embedded manifest lacks a string `name`; fix the manifest");
}
other => other,
} Prevention
- Deserialize the manifest into a typed struct (#[derive(Deserialize)] with required name: String) so missing names fail at parse time.
- Keep name and source adjacent in each [[capsule]] block to make omissions obvious in review.
- CI-check the manifest fixture with a linter/schema validator before it is embedded.
When it happens
Trigger: A `[[capsule]]` entry in UNICITY_CE_MANIFEST omits `name`, or sets `name` to a non-string TOML value (integer, boolean, inline table, array). Raised via capsule_assets_from_manifest when invoked by capsule_dir_with, prepare_unicity_ce_init, or install_capsule_fixtures.
Common situations: Hand-adding a capsule entry and forgetting the name field; a script generating the manifest writing an empty or numeric identifier; a schema migration where `name` was renamed (e.g. `package`); copy-pasting an entry and deleting the name line.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- embedded capsule has no source
- embedded distro has no capsules
- embedded capsule source has no asset
- [package].name is missing or empty.
- Subscribe ` ` has priority outside the u32 range.
AI-assisted analysis of unicity-aos/aos-ce@f6f22024fb (2026-09-13).
Data as JSON: /api/errors/f0f5c7b659454dcf.
Report an issue: GitHub.
Appendix: source
Thrown at crates/unicity-aos-bootstrap/src/lib.rs:663
let manifest = UNICITY_CE_MANIFEST
.parse::<toml::Value>()
.map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))?;
let capsules = manifest
.get("capsule")
.and_then(toml::Value::as_array)
.ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidData,
"embedded distro has no capsules",
)
})?;
let mut assets = Vec::with_capacity(capsules.len());
for capsule in capsules {
let package = capsule
.get("name")
.and_then(toml::Value::as_str)
.ok_or_else(|| {
io::Error::new(io::ErrorKind::InvalidData, "embedded capsule has no name")
})?;
let source = capsule
.get("source")
.and_then(toml::Value::as_str)
.ok_or_else(|| {
io::Error::new(io::ErrorKind::InvalidData, "embedded capsule has no source")
})?;
let relative = Path::new(source);
let mut components = relative.components();
if components.next() != Some(std::path::Component::Normal(OsStr::new("capsules")))
|| components
.next()
.and_then(|component| match component {
std::path::Component::Normal(name) => Some(name),
_ => None,
})
.is_none()
|| components.next().is_some()View on GitHub (pinned to f6f22024fb)