astrid-runtime/astrid · error
duplicate capsule name '{}'
Error message
duplicate capsule name '{}' What it means
Capsule names are used as unique keys (path components under the capsule store), so validate_manifest tracks names in a HashSet and bails on the second occurrence of the same name. Duplicate names would make capsule file placement and resolution ambiguous.
Source
Thrown at crates/astrid-cli/src/commands/distro/validate.rs:139
if manifest.capsules.is_empty() {
anyhow::bail!("distro must contain at least one capsule");
}
// No duplicate capsule names, and each name must be a valid
// identifier. Names become path components in the `.shuttle` layout
// (`capsules/<name>.capsule`) and on disk under the capsule store;
// constraining them to `^[a-z][a-z0-9-]*$` keeps a manifest from
// introducing `/`, `..`, or other path-hostile characters there.
let mut seen_names = HashSet::new();
for cap in &manifest.capsules {
if !is_valid_id(&cap.name) {
anyhow::bail!(
"capsule name '{}' is invalid (must match ^[a-z][a-z0-9-]*$)",
cap.name,
);
}
if !seen_names.insert(&cap.name) {
anyhow::bail!("duplicate capsule name '{}'", cap.name);
}
// Distros compose *released* capsules. `branch`/`rev` selectors
// can only be honored by compiling from a git ref — the exact
// toolchain dependency offline/headless distro seeding exists to
// remove. Reject them: a distro must pin a released `version` or
// `tag`. (Git-ref installs remain available via the standalone
// `astrid capsule install` command.)
if cap.branch.is_some() || cap.rev.is_some() {
anyhow::bail!(
"capsule '{}': branch/rev require building from source and are not allowed in a \
distro manifest — pin a released `version` or `tag` (git-ref installs are \
available via `astrid capsule install`).",
cap.name,
);
}
let version = cap.version.trim();
if cap.version != version {
anyhow::bail!(View on GitHub (pinned to affd8760f4)
Solutions
- Rename one of the duplicate capsules (must still match `^[a-z][a-z0-9-]*$`).
- Remove the redundant duplicate entry if it was accidental.
- Deduplicate programmatically when generating/merging manifests (e.g. last-one-wins or explicit merge policy).
Example fix
# before [[capsules]] name = "http" version = "1.0.0" [[capsules]] name = "http" version = "1.1.0" # after [[capsules]] name = "http" version = "1.1.0"
Defensive patterns
Strategy: validation
Validate before calling
let mut seen = std::collections::HashSet::new();
for cap in &manifest.capsules {
if !seen.insert(&cap.name) {
panic!("duplicate capsule name: {}", cap.name);
}
} Try / catch
if let Err(e) = validate_manifest(&manifest) {
if e.to_string().contains("duplicate capsule name") {
eprintln!("dedupe capsules: {e}");
}
} Prevention
- When copy-pasting capsule blocks, change the name immediately
- Deduplicate after merging manifests from multiple sources
- Key capsule entries by name in generator code to enforce uniqueness
When it happens
Trigger: A manifest with two or more `[[capsules]]` sections sharing the same `name` value.
Common situations: Copy-pasting a capsule block to add another version and forgetting to change the name; merging manifests from two sources that both include the same capsule.
Related errors
- distro.astrid-version '{av}' is not a valid semver requireme
- distro.requires.{ns}.{name} '{req}' is not a valid semver re
- distro must contain at least one capsule
- capsule name '{}' is invalid (must match ^[a-z][a-z0-9-]*$)
- capsule '{}': branch/rev require building from source and ar
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/54ca94a321a479d1.
Report an issue: GitHub.