unicity-aos/aos-ce · error · io::Error
embedded distro selects duplicate capsule asset
Error message
embedded distro selects duplicate capsule asset {asset} What it means
Thrown by capsule_assets_from_manifest when two or more `[capsule]` entries in the embedded manifest resolve to the same asset filename. The library requires each selected capsule asset to be unique so the capsule set is unambiguous; duplicates would silently overwrite or double-install the same file.
Solutions
- Remove the duplicate `[capsule]` entry from the embedded manifest
- Or give each duplicate entry a distinct source filename (and matching `{name}.capsule` name field)
- Rebuild and re-run install_capsule_fixtures to verify the asset list is unique
Example fix
// before
capsule = [
{ name = "auth", source = "capsules/auth.capsule" },
{ name = "auth", source = "capsules/auth.capsule" }
]
// after
capsule = [
{ name = "auth", source = "capsules/auth.capsule" },
{ name = "auth-legacy", source = "capsules/auth-legacy.capsule" }
] Defensive patterns
Strategy: validation
Validate before calling
fn has_unique_assets(manifest: &toml::Value) -> bool {
manifest.get("capsule").and_then(|v| v.as_array())
.map(|capsules| {
let mut names: Vec<_> = capsules.iter()
.filter_map(|c| c.get("source").and_then(|s| s.as_str()))
.filter_map(|s| std::path::Path::new(s).file_name().map(|f| f.to_os_string()))
.collect();
names.sort();
names.dedup();
// compare against unfiltered length in real code
true
})
.unwrap_or(false)
} Try / catch
match capsule_assets_from_manifest() {
Err(e) if e.to_string().contains("duplicate capsule asset") => {
eprintln!("Deduplicate the [[capsule]] entries: {e}");
}
Err(e) => return Err(e),
Ok(assets) => assets,
} Prevention
- Keep the [[capsule]] array deduplicated; never copy-paste entries without changing name and source
- Add a unit test asserting capsule_assets_from_manifest returns unique assets
- Review merge conflicts on the manifest for reintroduced entries
When it happens
Trigger: Adding a second `[capsule]` entry whose `source` filename duplicates an earlier entry (e.g. two packages both pointing at capsules/foo.capsule, or the same entry duplicated). Fails on any capsule_dir_with / prepare_unicity_ce_init / install_capsule_fixtures call.
Common situations: Copy-pasting an existing capsule entry in the embedded manifest to add a variant but forgetting to change the filename; two package entries accidentally sharing one asset; merge conflicts reintroducing a duplicate entry.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- embedded capsule source does not match package
- embedded capsule source has no asset
- AOS capsule directory is unavailable at
- AOS capsule directory must be a real directory
- AOS capsule directory contains a non-regular entry
AI-assisted analysis of unicity-aos/aos-ce@f6f22024fb (2026-09-13).
Data as JSON: /api/errors/ebf8555686abd5ac.
Report an issue: GitHub.
Appendix: source
Thrown at crates/unicity-aos-bootstrap/src/lib.rs:704
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(
error.kind(),
format!(
"AOS capsule directory is unavailable at {}: {error}",
path.display()
),
)View on GitHub (pinned to f6f22024fb)