astrid-runtime/astrid · error

capsule version mismatch for '{id}': expected '{expected_ver

Error message

capsule version mismatch for '{id}': expected '{expected_version}', manifest declares '{installed_version}'

What it means

This is the internal-layer version check: after resolving the id, install_from_local_path_internal compares manifest.package.version against expected.version (when provided). Any difference aborts the install with this message, ensuring the exact approved version is what lands in the store/workspace. It fires for wrappers that pass an expected identity with a version pinned.

Source

Thrown at crates/astrid-capsule-install/src/local.rs:585

    let manifest_path = source_dir.join("Capsule.toml");
    if !manifest_path.exists() {
        bail!("No Capsule.toml found in {}", source_dir.display());
    }
    let manifest = load_manifest(&manifest_path).context("failed to load Capsule manifest")?;
    let id = CapsuleId::new(manifest.package.name.clone())?;
    if let Some(expected) = expected
        && id != *expected.id
    {
        bail!(
            "capsule identity mismatch: expected '{}', manifest declares '{id}'",
            expected.id
        );
    }
    let installed_version = manifest.package.version.clone();
    if let Some(expected_version) = expected.and_then(|expected| expected.version)
        && installed_version != expected_version
    {
        bail!(
            "capsule version mismatch for '{id}': expected '{expected_version}', manifest declares '{installed_version}'"
        );
    }

    // Re-verify the exact source immediately before any target mutation. This
    // closes the gap between pre-install approval and the transactional copy,
    // including provenance-envelope swaps that leave content bytes unchanged.
    let installed_authority =
        authority_for_install_source(source_dir, &manifest, installed_authority)?;

    #[cfg(test)]
    run_post_authority_test_hook(source_dir);

    // An approval may have been captured by an earlier inspection. Recheck the
    // decision-bound source digest before any install read or target mutation.
    let mut installed_authority =
        authority_for_install_source(source_dir, &manifest, Some(installed_authority))?;

View on GitHub (pinned to affd8760f4)

Solutions

  1. Align expected.version with package.version in the source Capsule.toml (read the manifest first and use its version)
  2. Or pin the source tree back to the expected version (git checkout the tag/commit for that version)
  3. Re-run the authorization/approval flow for the new version if the bump is intentional
  4. Check for automation (release tooling) that bumps package.version unexpectedly

Example fix

// before
let expected = ExpectedCapsuleIdentity { id: &id, version: Some(Version::parse("2.0.0")?) };
// after
let manifest: Manifest = toml::from_str(&std::fs::read_to_string(src.join("Capsule.toml"))?)?;
let expected = ExpectedCapsuleIdentity { id: &id, version: Some(manifest.package.version.clone()) };
Defensive patterns

Strategy: validation

Validate before calling

fn check_version(src: &Path, expected_version: Option<&Version>) -> anyhow::Result<()> {
    if let Some(want) = expected_version {
        let manifest: Manifest = toml::from_str(&std::fs::read_to_string(src.join("Capsule.toml"))?)?;
        anyhow::ensure!(&manifest.package.version == want, "version drift: {} != {want}", manifest.package.version);
    }
    Ok(())
}

Try / catch

match install_result {
    Err(e) if e.to_string().contains("capsule version mismatch") => {
        // re-pin source or re-approve current manifest version
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling install_from_local_path_internal (or its wrappers: unpack_and_install_internal, install_from_local_path_for_principal_in_workspace, etc.) with ExpectedCapsuleIdentity.version = Some(v) while the source Capsule.toml declares a different package.version.

Common situations: Local checkout updated to a newer release after the version was pinned by a resolver/lockfile; patch bump of package.version between approval and install; hand-edited manifest; installing from a branch that advanced the version.

Related errors


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