{"record":{"id":"5943a5158e44aa30","repo":"astrid-runtime/astrid","slug":"durable-capsule-id-identity-differs-across-archi","errorCode":null,"errorMessage":"durable capsule {id} identity differs across archive and authority","messagePattern":"durable capsule (.+?) identity differs across archive and authority","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/astrid-capsule-install/src/storage.rs","lineNumber":267,"sourceCode":"}\n\nfn verify_package_identity(\n    id: &str,\n    manifest: &CapsuleManifest,\n    metadata: &CapsuleMeta,\n    authority: &InstalledAuthority,\n    manifest_bytes: &[u8],\n    verification: &ArtifactVerification,\n    archive_files: &std::collections::BTreeMap<String, Vec<u8>>,\n) -> anyhow::Result<()> {\n    if authority.schema_version != 1 {\n        bail!(\n            \"durable capsule {id} has unsupported authority schema {}\",\n            authority.schema_version\n        );\n    }\n    if authority.capsule_id != id || manifest.package.name != id {\n        bail!(\"durable capsule {id} identity differs across archive and authority\");\n    }\n    if authority.version != manifest.package.version || metadata.version != authority.version {\n        bail!(\"durable capsule {id} version differs across package records\");\n    }\n    let manifest_digest = crate::authority::digest_manifest(manifest_bytes);\n    if authority.manifest_digest != manifest_digest {\n        bail!(\"durable capsule {id} manifest digest differs from authority receipt\");\n    }\n    if authority.content_digest != verification.content_digest() {\n        bail!(\"durable capsule {id} content digest differs from authority receipt\");\n    }\n    let expected_imports = crate::wit::version_map_to_strings(&manifest.imports, |definition| {\n        definition.version.to_string()\n    });\n    if metadata.imports != expected_imports {\n        bail!(\"durable capsule {id} imports differ between metadata and archive\");\n    }\n    let expected_exports = crate::wit::version_map_to_strings(&manifest.exports, |definition| {","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-capsule-install/src/storage.rs#L249-L285","documentation":"This error is thrown by verify_package_identity when a capsule's identity is not consistent across the two sources of truth: the authority receipt's capsule_id and the archive manifest's package.name must both equal the requested capsule id. The library treats this as tampering or corruption — a capsule whose archive and signed authority record disagree about who it is must never be installed or loaded. It guards the durable install path (read_verified_durable_package_for_owner) against mismatched or repackaged artifacts.","triggerScenarios":"Calling read_verified_durable_package_for_owner (or the test-path durable_metadata_cross_binding_rejects_manifest_and_archive_mismatches) with an archive where manifest.package.name != the requested id, or where the InstalledAuthority receipt was issued for a different capsule_id than the one being resolved.","commonSituations":"Manually renaming a package in CapsuleManifest without reissuing the authority receipt; mixing up archive files between two capsules during copy/restore; installing a capsule under a different id/owner directory than it was signed for; hand-edited metadata after an interrupted install.","solutions":["Reinstall the capsule from a freshly published archive so the authority receipt and manifest are regenerated together.","Check that the id passed to read_verified_durable_package_for_owner exactly matches manifest.package.name in the archive (case-sensitive).","Reissue the authority record with the correct capsule_id if the package was legitimately renamed.","Inspect the install directory for cross-contaminated manifest/authority files and remove the corrupted capsule."],"exampleFix":"// before: loading capsule under mismatched id\nlet pkg = store.read_verified_durable_package_for_owner(owner, \"my-capsule\")?;\n// after: ensure the id matches the manifest's package name before loading\nlet manifest = parse_manifest(&archive_bytes)?;\nassert_eq!(manifest.package.name, \"my-capsule\");\nlet pkg = store.read_verified_durable_package_for_owner(owner, \"my-capsule\")?;","handlingStrategy":"validation","validationCode":"fn capsule_identity_matches(id: &str, manifest: &CapsuleManifest, authority: &InstalledAuthority) -> bool {\n    authority.capsule_id == id && manifest.package.name == id\n}\n// call before read_verified_durable_package_for_owner","typeGuard":"fn is_expected_capsule(a: &InstalledAuthority, id: &str) -> bool { a.capsule_id == id }","tryCatchPattern":"match store.read_verified_durable_package_for_owner(owner, id) {\n    Ok(pkg) => pkg,\n    Err(e) if e.to_string().contains(\"identity differs across archive and authority\") => {\n        // reinstall from canonical archive\n        store.install(owner, &canonical_archive)?\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always install capsules via the library's install flow; never hand-copy manifest or authority files between capsule directories.","Keep the id used for lookups identical to manifest.package.name (case-sensitive).","Reissue the authority receipt whenever a package is renamed.","After restores/migrations, verify identity fields before first load."],"tags":["integrity","capsule","identity-mismatch","rust"],"backgroundTag":"invalid-identifier","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"}