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
- Align expected.version with package.version in the source Capsule.toml (read the manifest first and use its version)
- Or pin the source tree back to the expected version (git checkout the tag/commit for that version)
- Re-run the authorization/approval flow for the new version if the bump is intentional
- 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
- Pin the source checkout to the approved version tag before installing
- Re-run approval after any version bump
- Disable version-bumping automation during install windows
- Compare manifest version to the lockfile entry before calling the API
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
- capsule version mismatch for '{expected}': expected '{expect
- capsule identity or version changed after authority decision
- capsule identity mismatch: expected '{expected}', manifest d
- No Capsule.toml found in {}
- capsule identity mismatch: expected '{}', manifest declares
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/218c291b2534d633.
Report an issue: GitHub.