{"record":{"id":"218c291b2534d633","repo":"astrid-runtime/astrid","slug":"capsule-version-mismatch-for-id-expected-ex","errorCode":null,"errorMessage":"capsule version mismatch for '{id}': expected '{expected_version}', manifest declares '{installed_version}'","messagePattern":"capsule version mismatch for '(.+?)': expected '(.+?)', manifest declares '(.+?)'","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-capsule-install/src/local.rs","lineNumber":585,"sourceCode":"    let manifest_path = source_dir.join(\"Capsule.toml\");\n    if !manifest_path.exists() {\n        bail!(\"No Capsule.toml found in {}\", source_dir.display());\n    }\n    let manifest = load_manifest(&manifest_path).context(\"failed to load Capsule manifest\")?;\n    let id = CapsuleId::new(manifest.package.name.clone())?;\n    if let Some(expected) = expected\n        && id != *expected.id\n    {\n        bail!(\n            \"capsule identity mismatch: expected '{}', manifest declares '{id}'\",\n            expected.id\n        );\n    }\n    let installed_version = manifest.package.version.clone();\n    if let Some(expected_version) = expected.and_then(|expected| expected.version)\n        && installed_version != expected_version\n    {\n        bail!(\n            \"capsule version mismatch for '{id}': expected '{expected_version}', manifest declares '{installed_version}'\"\n        );\n    }\n\n    // Re-verify the exact source immediately before any target mutation. This\n    // closes the gap between pre-install approval and the transactional copy,\n    // including provenance-envelope swaps that leave content bytes unchanged.\n    let installed_authority =\n        authority_for_install_source(source_dir, &manifest, installed_authority)?;\n\n    #[cfg(test)]\n    run_post_authority_test_hook(source_dir);\n\n    // An approval may have been captured by an earlier inspection. Recheck the\n    // decision-bound source digest before any install read or target mutation.\n    let mut installed_authority =\n        authority_for_install_source(source_dir, &manifest, Some(installed_authority))?;\n","sourceCodeStart":567,"sourceCodeEnd":603,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-capsule-install/src/local.rs#L567-L603","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nlet expected = ExpectedCapsuleIdentity { id: &id, version: Some(Version::parse(\"2.0.0\")?) };\n// after\nlet manifest: Manifest = toml::from_str(&std::fs::read_to_string(src.join(\"Capsule.toml\"))?)?;\nlet expected = ExpectedCapsuleIdentity { id: &id, version: Some(manifest.package.version.clone()) };","handlingStrategy":"validation","validationCode":"fn check_version(src: &Path, expected_version: Option<&Version>) -> anyhow::Result<()> {\n    if let Some(want) = expected_version {\n        let manifest: Manifest = toml::from_str(&std::fs::read_to_string(src.join(\"Capsule.toml\"))?)?;\n        anyhow::ensure!(&manifest.package.version == want, \"version drift: {} != {want}\", manifest.package.version);\n    }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":"match install_result {\n    Err(e) if e.to_string().contains(\"capsule version mismatch\") => {\n        // re-pin source or re-approve current manifest version\n    }\n    other => other?,\n}","preventionTips":["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"],"tags":["capsule-install","version-mismatch","manifest"],"backgroundTag":"version-mismatch","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}