unicity-aos/aos-ce · error · std::io::Error
embedded distro has no capsules
Error message
embedded distro has no capsules
What it means
capsule_assets_from_manifest parses the compile-time-embedded UNICITY_CE_MANIFEST TOML and extracts the `capsule` array. This error is thrown when the embedded manifest either has no top-level `capsule` key at all, or the key exists but is not a TOML array. It signals that the embedded distro manifest is malformed and no capsule assets can be enumerated.
Solutions
- Add at least one `[[capsule]]` array-of-tables entry to the embedded manifest (UNICITY_CE_MANIFEST / the distro manifest file feeding it).
- Check the key spelling and type: it must be exactly `capsule` and an array of tables (`[[capsule]]`), not `[capsule]` or `capsules`.
- If the distro genuinely ships no capsules, treat that as a build-time failure: populate the manifest via the distro build script rather than stubbing it empty.
- Regenerate the manifest from the canonical source with the project's build/embed tooling instead of editing it by hand.
Example fix
// before (manifest has no capsule array) [distro] version = "1.0" // after [distro] version = "1.0" [[capsule]] name = "my-package" source = "capsules/my-package.capsule"
Defensive patterns
Strategy: validation
Validate before calling
// Rust: validate the embedded manifest shape before calling the API
fn ensure_manifest_has_capsules(manifest_toml: &str) -> Result<(), String> {
let value: toml::Value =
toml::from_str(manifest_toml).map_err(|e| format!("manifest TOML invalid: {e}"))?;
match value.get("capsule").and_then(toml::Value::as_array) {
Some(arr) if !arr.is_empty() => Ok(()),
_ => Err("embedded manifest has no `capsule` array-of-tables".into()),
}
} Type guard
fn has_capsule_array(manifest: &toml::Value) -> bool {
manifest.get("capsule").map(toml::Value::is_array).unwrap_or(false)
} Try / catch
match prepare_unicity_ce_init(...) {
Err(e) if e.to_string().contains("embedded distro has no capsules") => {
eprintln!("build bug: embedded CE manifest lacks [[capsule]] entries; regenerate manifest");
}
Err(e) => return Err(e),
Ok(v) => v,
} Prevention
- Always emit `[[capsule]]` array-of-tables entries from the distro build script; never hand-edit the embedded manifest.
- Add a unit test that parses UNICITY_CE_MANIFEST and asserts a non-empty `capsule` array exists.
- Validate the manifest against a schema (e.g. serde struct with required Vec<Capsule>) at build time.
When it happens
Trigger: Calling capsule_assets_from_manifest (directly or via capsule_dir_with, prepare_unicity_ce_init, install_capsule_fixtures) when UNICITY_CE_MANIFEST lacks a `capsule = [...]` table array — e.g. the manifest only has other sections like [package], or `capsule` is declared as a plain table/string instead of an array of tables.
Common situations: Regenerating or hand-editing the embedded distro manifest and accidentally renaming or dropping the `[[capsule]]` section; a build script emitting a manifest template with no capsule entries; a schema/version change where the key was renamed (e.g. to `capsules`); committing an empty or placeholder manifest fixture.
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
- embedded capsule has no source
- 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/640e24ae9ca63a40.
Report an issue: GitHub.
Appendix: source
Thrown at crates/unicity-aos-bootstrap/src/lib.rs:652
}
const fn runtime_binary_name() -> &'static str {
RUNTIME_EXECUTABLE_NAMES[0]
}
const fn runtime_daemon_binary_name() -> &'static str {
RUNTIME_EXECUTABLE_NAMES[1]
}
fn capsule_assets_from_manifest() -> io::Result<Vec<String>> {
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")
})?;View on GitHub (pinned to f6f22024fb)