unicity-aos/aos-ce · error · io::Error
embedded distro has no capsules
Error message
embedded distro has no capsules
What it means
unicity_ce_capsule_names parses the embedded distribution manifest as TOML and requires a top-level `capsule` array. If the manifest is present but has no `capsule` key (or it is not an array), the function maps that to an InvalidData io::Error with this message. It signals that the bundled distro manifest is structurally invalid for migration.
Solutions
- Rebuild the bootstrap distro so its embedded manifest includes a `capsule` array of tables
- Inspect the embedded manifest with `toml` tooling to confirm the `capsule` key exists and is an array
- Verify the packaging pipeline is embedding the correct manifest file and not a stub/older version
Example fix
# before (manifest.toml embedded in distro) [meta] version = 1 # after [meta] version = 1 [[capsule]] name = "core"
Defensive patterns
Strategy: validation
Validate before calling
fn manifest_has_capsules(manifest: &str) -> bool {
toml::from_str::<toml::Value>(manifest)
.ok()
.and_then(|v| v.get("capsule").and_then(|c| c.as_array()).map(|a| !a.is_empty()))
.unwrap_or(false)
} Type guard
fn has_capsule_array(manifest: &toml::Value) -> Option<&Vec<toml::Value>> {
manifest.get("capsule").and_then(|c| c.as_array())
} Try / catch
match unicity_ce_capsule_names() {
Ok(names) => proceed(names),
Err(e) if e.to_string().contains("embedded distro has no capsules") =>
eprintln!("distro manifest missing capsule section; rebuild distro"),
Err(e) => return Err(e),
} Prevention
- Schema-validate the embedded distro manifest at build time
- Add a CI check that every distro manifest contains a non-empty capsule array
- Never hand-edit the embedded manifest; regenerate it from the upstream source
When it happens
Trigger: Calling archive_inactive_activation_state (which calls unicity_ce_capsule_names) against a bootstrap distro whose embedded manifest TOML lacks a `[capsule]` array, or defines `capsule` as a table/string instead of an array of tables.
Common situations: A distro image built from an older manifest schema before the `capsule` section was introduced; a hand-edited or truncated embedded manifest; packaging tooling stripping the section during build.
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 name
- must not be empty
- embedded capsule source has no asset
- AOS capsule directory must be valid UTF-8 for the TOML…
- standalone runtime has no existing system lock; refusing an…
AI-assisted analysis of unicity-aos/aos-ce@f6f22024fb (2026-09-13).
Data as JSON: /api/errors/bfac5155b1526c6d.
Report an issue: GitHub.
Appendix: source
Thrown at crates/unicity-aos-bootstrap/src/migration.rs:462
if name != OsStr::new("default.toml") {
inactive_profiles.push(PathBuf::from("etc/profiles").join(name));
}
}
for relative in inactive_profiles {
archive_path(staging, &relative, entries)?;
}
Ok(())
}
fn unicity_ce_capsule_names() -> io::Result<HashSet<String>> {
let manifest = crate::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",
)
})?;
capsules
.iter()
.map(|capsule| {
capsule
.get("name")
.and_then(toml::Value::as_str)
.map(str::to_owned)
.ok_or_else(|| {
io::Error::new(io::ErrorKind::InvalidData, "embedded capsule has no name")
})
})
.collect()
}
View on GitHub (pinned to f6f22024fb)