astrid-runtime/astrid · error

signed Distro.lock contains undeclared capsule

Error message

signed Distro.lock contains undeclared capsule '{}'

What it means

While walking the signed Distro.lock, every lock entry must correspond to a capsule declared in Distro.toml. If a lock capsule's name has no declared counterpart, the lock references something the signed manifest never authorized — a supply-chain red flag — so validation aborts with this message naming the offending capsule.

Solutions

  1. Regenerate and re-sign Distro.lock from the current Distro.toml so both member sets match
  2. If the capsule should still exist, re-add its declaration to Distro.toml and re-seal
  3. Remove the stale capsule entry from Distro.lock and republish

Example fix

# before: lock has 'legacy' but toml doesn't
capsules = ["alpha", "legacy"]   # lock
capsules = ["alpha"]             # toml
# after: regenerate lock
capsules = ["alpha"]             # lock (regenerated & re-signed)
Defensive patterns

Strategy: validation

Validate before calling

let declared: HashSet<&str> = manifest.capsules.iter().map(|c| c.name.as_str()).collect();
let extra: Vec<_> = lock.capsules.iter().map(|c| c.name.as_str()).filter(|n| !declared.contains(n)).collect();
if !extra.is_empty() { eprintln!("lock has undeclared capsules: {extra:?}"); }

Try / catch

match validate_signed_member_sets(manifest, lock) {
    Err(e) if e.to_string().contains("undeclared capsule") => {
        eprintln!("Lock references a capsule removed from Distro.toml; regenerate + re-seal the lock");
    }
    r => r?,
}

Prevention

When it happens

Trigger: fetch_signed_manifest -> verify_signed_manifest -> validate_signed_member_sets when Distro.lock contains a capsule name that Distro.toml does not declare (e.g. lock left over from a removed capsule, or a tampered lock).

Common situations: A capsule was deleted from Distro.toml but Distro.lock was not regenerated before re-sealing/publishing; restoring an old lock file over a newer manifest; manual lock editing.

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


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

Appendix: source

Thrown at crates/astrid-cli/src/commands/init_signed_source.rs:354

    {
        bail!("Distro.lock identity does not match the signed Distro.toml");
    }

    let declared: HashMap<&str, &DistroCapsule> = manifest
        .capsules
        .iter()
        .map(|capsule| (capsule.name.as_str(), capsule))
        .collect();
    anyhow::ensure!(
        declared.len() == manifest.capsules.len() && lock.capsules.len() == declared.len(),
        "signed Distro.lock members do not match Distro.toml declarations"
    );
    for capsule in &lock.capsules {
        let declared_capsule = declared
            .get(capsule.name.as_str())
            .copied()
            .ok_or_else(|| {
                anyhow::anyhow!(
                    "signed Distro.lock contains undeclared capsule '{}'",
                    capsule.name
                )
            })?;
        if capsule.source != declared_capsule.source || capsule.version != declared_capsule.version
        {
            bail!(
                "signed Distro.lock entry '{}' does not match Distro.toml",
                capsule.name
            );
        }
        anyhow::ensure!(
            !capsule.hash.is_empty(),
            "signed Distro.lock entry '{}' has no capsule hash",
            capsule.name
        );
    }
    Ok(())

View on GitHub (pinned to affd8760f4)