astrid-runtime/astrid · error

source produced {} .capsule archives but no capsule name to

Error message

source produced {} .capsule archives but no capsule name to pick one; expected an archive named '<capsule>.capsule'

What it means

After a GitHub source build produces .capsule archives, pick_capsule must select one. With a single archive it picks it; with several, it needs a name hint (the capsule name) to disambiguate. If multiple archives were produced and name_hint is None, it cannot choose and errors instead of guessing.

Source

Thrown at crates/astrid-capsule-install/src/github_source.rs:127

        .collect()
}

/// Choose which `.capsule` to install when a source yields several. A monorepo
/// builds/releases one archive per capsule crate, named `<capsule>.capsule`, so
/// picking "the first" would install the wrong one. Returns the index into
/// `names` of the chosen archive.
///
/// * none        -> `Ok(None)` (caller falls back, e.g. release -> clone+build).
/// * exactly one -> `Ok(Some(0))` — unambiguous; `name_hint` is irrelevant.
/// * several     -> the one named `<name_hint>.capsule`. Without a hint, or with
///   no matching name, refuse rather than silently install the wrong capsule.
pub fn pick_capsule(names: &[&str], name_hint: Option<&str>) -> anyhow::Result<Option<usize>> {
    match names {
        [] => Ok(None),
        [_] => Ok(Some(0)),
        many => {
            let Some(hint) = name_hint else {
                bail!(
                    "source produced {} .capsule archives but no capsule name to pick one; \
                     expected an archive named '<capsule>.capsule'",
                    many.len()
                );
            };
            // Match the hint against each candidate's stem via `strip_suffix`
            // (no per-call allocation) rather than `format!`-ing the target.
            match many
                .iter()
                .position(|n| n.strip_suffix(".capsule") == Some(hint))
            {
                Some(idx) => Ok(Some(idx)),
                None => bail!(
                    "no '.capsule' archive named '{hint}.capsule' among [{}]",
                    many.join(", ")
                ),
            }
        },

View on GitHub (pinned to affd8760f4)

Solutions

  1. Re-run the install with the capsule name so name_hint is Some and can disambiguate the archives (e.g. `install owner/repo <capsule-name>`).
  2. Delete extra .capsule artifacts from the build output so only one archive remains, or build only the target capsule.
  3. Rename the produced archives so exactly one follows the `<capsule>.capsule` convention and re-run.

Example fix

// before
resolve_capsule_to_file(&source, None)?;
// after
resolve_capsule_to_file(&source, Some("my-capsule"))?;
Defensive patterns

Strategy: validation

Validate before calling

// caller-side check before resolving:
if capsule_names.len() > 1 && name_hint.is_none() {
    return Err(anyhow::anyhow!(
        "multiple .capsule archives produced ({:?}); pass the capsule name", capsule_names));
}

Type guard

fn can_pick(names: &[&str], hint: Option<&str>) -> bool {
    match names.len() { 0 | 1 => true, _ => hint.is_some() }
}

Try / catch

match pick_capsule(&names, hint) {
    Err(e) if e.to_string().contains("no capsule name to pick") => {
        eprintln!("build produced {} archives; re-run with the capsule name", names.len());
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling pick_capsule (via install_from_github, resolve_capsule_to_file, or clone_and_build) with names.len() > 1 and name_hint = None — i.e. the build emitted two or more .capsule files and no capsule name was supplied to match against archive stems.

Common situations: A monorepo GitHub repo whose build produces multiple .capsule artifacts while the user ran an install command without naming the capsule; a script calling resolve_capsule_to_file without passing the name; a renamed capsule so the expected `<name>.capsule` convention no longer matches the configured name.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/a99812b1df994835. Report an issue: GitHub.