{"record":{"id":"9de59376083081f4","repo":"astrid-runtime/astrid","slug":"durable-capsule-id-metadata-executable-hash-diff","errorCode":null,"errorMessage":"durable capsule {id} metadata executable hash differs from authority receipt","messagePattern":"durable capsule (.+?) metadata executable hash differs from authority receipt","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-capsule-install/src/storage.rs","lineNumber":292,"sourceCode":"        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| {\n        definition.version.to_string()\n    });\n    if metadata.exports != expected_exports {\n        bail!(\"durable capsule {id} exports differ between metadata and archive\");\n    }\n    if authority.wasm_hash_pinned && metadata.wasm_hash != authority.approved_wasm_hash {\n        bail!(\"durable capsule {id} metadata executable hash differs from authority receipt\");\n    }\n    if let Some(component) = manifest.components.first() {\n        let Some(relative) = component.path.to_str() else {\n            bail!(\"durable capsule {id} component path is not UTF-8\");\n        };\n        let Some(bytes) = archive_files.get(relative) else {\n            bail!(\"durable capsule {id} component is missing from its archive\");\n        };\n        if Path::new(relative)\n            .extension()\n            .is_some_and(|extension| extension.eq_ignore_ascii_case(\"wasm\"))\n        {\n            let archive_hash = blake3::hash(bytes).to_hex().to_string();\n            if authority.wasm_hash_pinned\n                && authority.approved_wasm_hash.as_deref() != Some(archive_hash.as_str())\n            {\n                bail!(\"durable capsule {id} WASM hash differs between authority and archive\");\n            }","sourceCodeStart":274,"sourceCodeEnd":310,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-capsule-install/src/storage.rs#L274-L310","documentation":"verify_package_identity checks that, when the authority receipt pins a WASM hash (wasm_hash_pinned), the wasm_hash recorded in the capsule metadata equals the authority's approved_wasm_hash. This bail fires when the metadata's executable hash disagrees with the approved hash, i.e. the metadata references an executable that was never approved by the authority. It guards against installing a capsule whose metadata claims a different binary than the one the authority signed off on.","triggerScenarios":"Calling read_verified_durable_package_for_owner on a capsule where authority.wasm_hash_pinned is true and metadata.wasm_hash != authority.approved_wasm_hash — e.g. metadata was regenerated for a rebuilt component while the authority receipt still pins the previously approved hash.","commonSituations":"Recompiling the WASM component after approval (new blake3 hash) but keeping the old authority receipt; pointing an install at a newer capsule version than the one the authority approved; copying metadata from another capsule build; hand-editing the wasm_hash field.","solutions":["Obtain a new authority receipt whose approved_wasm_hash matches the metadata's wasm_hash (re-approval of the rebuilt component).","Install the exact capsule build the authority approved, so metadata.wasm_hash equals approved_wasm_hash.","If the pin is no longer wanted, have the authority re-issue the receipt without a pinned WASM hash (wasm_hash_pinned = false).","Print both hashes (metadata.wasm_hash vs authority.approved_wasm_hash) to confirm which build is stale."],"exampleFix":"// before: rebuilt wasm, stale receipt\nassert_ne!(metadata.wasm_hash, authority.approved_wasm_hash);\n// after: refresh the authority receipt for the new build\nlet authority = request_approval(&new_build); // approved_wasm_hash == metadata.wasm_hash\ninstall_with_authority(&package, &authority);","handlingStrategy":"validation","validationCode":"if authority.wasm_hash_pinned && metadata.wasm_hash != authority.approved_wasm_hash {\n    return Err(anyhow!(\"metadata hash {:?} not approved (receipt: {:?})\", metadata.wasm_hash, authority.approved_wasm_hash));\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Re-issue the authority receipt whenever the component is rebuilt.","Pin capsule versions to receipts and never mix builds from different versions.","Log both hashes on mismatch to identify the stale artifact quickly."],"tags":["integrity-verification","wasm-hash","authority-receipt","rust"],"backgroundTag":"checksum-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"}