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

embedded capsule source does not match package

Error message

embedded capsule source does not match package {package}

What it means

This error is thrown by capsule_assets_from_manifest when a capsule entry in the embedded Community Edition TOML manifest has a `source` path whose filename is not `<package>.capsule`, where `<package>` is the entry's `name` field. The bootstrap library enforces a strict naming convention so that embedded capsule assets can be located and validated deterministically; any drift between the package name and the asset filename breaks that invariant.

Solutions

  1. Rename the asset in the `source` path so its filename is exactly `{name}.capsule` for that manifest entry
  2. Or update the entry's `name` field to match the existing filename (minus the .capsule extension)
  3. Re-run prepare_unicity_ce_init to confirm the embedded manifest passes validation

Example fix

// before
capsule = [{ name = "kernel-core", source = "capsules/kernel-core-v2.capsule" }]
// after
capsule = [{ name = "kernel-core", source = "capsules/kernel-core.capsule" }]
Defensive patterns

Strategy: validation

Validate before calling

fn capsule_source_matches(capsule: &toml::Value) -> bool {
    let name = capsule.get("name").and_then(|v| v.as_str());
    let source = capsule.get("source").and_then(|v| v.as_str());
    match (name, source) {
        (Some(n), Some(s)) => {
            std::path::Path::new(s).file_name().map(|f| f.to_string_lossy())
                == Some(format!("{n}.capsule"))
        }
        _ => false,
    }
}

Type guard

fn is_valid_capsule_entry(c: &toml::Value) -> bool {
    c.get("name").and_then(|v| v.as_str()).is_some()
        && c.get("source").and_then(|v| v.as_str()).is_some()
}

Try / catch

match bootstrap::prepare_unicity_ce_init(&home) {
    Err(e) if e.to_string().contains("does not match package") => {
        eprintln!("Manifest entry name/source mismatch: {e}");
    }
    Err(e) => return Err(e),
    Ok(v) => v,
}

Prevention

When it happens

Trigger: Editing the embedded UNICITY_CE_MANIFEST so a `[capsule]` entry's `source` filename does not equal the `name` field plus the `.capsule` extension (e.g. name="foo", source="capsules/foo_v2.capsule"). Any call to capsule_dir_with, prepare_unicity_ce_init, or install_capsule_fixtures then fails.

Common situations: Renaming a capsule package without renaming its .capsule asset file (or vice versa); hand-editing the embedded manifest; adding a new capsule entry with a versioned or suffixed filename; copy-pasting a capsule entry and updating only one of the two fields.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at crates/unicity-aos-bootstrap/src/lib.rs:698

                .is_none()
            || components.next().is_some()
            || relative.extension() != Some(OsStr::new("capsule"))
        {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                format!("embedded capsule source is not canonical: {source}"),
            ));
        }
        let asset = relative
            .file_name()
            .expect("validated capsule source has a filename")
            .to_str()
            .ok_or_else(|| {
                io::Error::new(io::ErrorKind::InvalidData, "capsule asset is not UTF-8")
            })?
            .to_owned();
        if asset != format!("{package}.capsule") {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                format!("embedded capsule source does not match package {package}"),
            ));
        }
        if assets.contains(&asset) {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                format!("embedded distro selects duplicate capsule asset {asset}"),
            ));
        }
        assets.push(asset);
    }
    Ok(assets)
}

fn validate_capsule_dir(path: &Path, expected: &[String]) -> io::Result<PathBuf> {
    let metadata = fs::symlink_metadata(path).map_err(|error| {
        io::Error::new(

View on GitHub (pinned to f6f22024fb)