unicity-aos/aos-ce · error · io::Error

embedded capsule has no name

Error message

embedded capsule has no name

What it means

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.

Solutions

  1. Add a `name` string field to every `[[capsule]]` entry in the embedded distro manifest
  2. Validate the manifest against the expected schema before embedding it in the distro
  3. Rebuild the distro from an upstream manifest rather than editing the embedded copy by hand

Example fix

# before
[[capsule]]
version = "1.2.0"

# after
[[capsule]]
name = "core"
version = "1.2.0"
Defensive patterns

Strategy: validation

Validate before calling

fn all_capsules_named(manifest: &str) -> bool {
    toml::from_str::<toml::Value>(manifest).ok()
        .and_then(|v| v.get("capsule").and_then(|c| c.as_array()).cloned())
        .map(|caps| caps.iter().all(|c| c.get("name").and_then(|n| n.as_str()).map(|s| !s.is_empty()).unwrap_or(false)))
        .unwrap_or(false)
}

Type guard

fn capsule_name(capsule: &toml::Value) -> Option<&str> {
    capsule.get("name").and_then(|n| n.as_str())
}

Try / catch

match unicity_ce_capsule_names() {
    Ok(names) => proceed(names),
    Err(e) if e.to_string().contains("embedded capsule has no name") =>
        eprintln!("a [[capsule]] entry is missing its name field"),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

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


AI-assisted analysis of unicity-aos/aos-ce@f6f22024fb (2026-09-13). Data as JSON: /api/errors/8233668a38abd6f1. Report an issue: GitHub.

Appendix: source

Thrown at crates/unicity-aos-bootstrap/src/migration.rs:475

        .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()
}

fn archive_path(staging: &Path, relative: &Path, entries: &mut [Entry]) -> io::Result<()> {
    if !is_safe_relative(relative) {
        return invalid("imported activation path is unsafe");
    }
    let archived = Path::new(IMPORT_ARCHIVE_DIR).join(relative);
    let source = staging.join(relative);
    let destination = staging.join(&archived);
    if destination.exists() {
        return invalid("imported activation archive contains a duplicate path");
    }
    create_private_dir(destination.parent().expect("archive path has a parent"))?;
    fs::rename(&source, &destination)?;
    sync_parent(&source)?;

View on GitHub (pinned to f6f22024fb)