{"record":{"id":"39af51c3efab97a6","repo":"astrid-runtime/astrid","slug":"distro-lock-capsule-capsule-does-not-declare-w","errorCode":null,"errorMessage":"Distro.lock capsule '{capsule}' does not declare WASM but installed metadata carries a WASM hash","messagePattern":"Distro\\.lock capsule '(.+?)' does not declare WASM but installed metadata carries a WASM hash","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/init_grant.rs","lineNumber":373,"sourceCode":"    capsule: &CapsuleId,\n    manifest: &CapsuleManifest,\n    meta_hash: Option<&str>,\n    locked_hash: &str,\n    store: Option<&astrid_storage::RuntimePrincipalStore>,\n) -> anyhow::Result<()> {\n    let declares_wasm = manifest_declares_wasm(manifest);\n    let Some(meta_hash) = meta_hash else {\n        if declares_wasm {\n            bail!(\"Distro.lock capsule '{capsule}' declares WASM but has no installed WASM hash\");\n        }\n        if !locked_hash.is_empty() {\n            bail!(\"Distro.lock non-WASM capsule '{capsule}' must not carry a WASM hash\");\n        }\n        return Ok(());\n    };\n\n    if !declares_wasm {\n        bail!(\n            \"Distro.lock capsule '{capsule}' does not declare WASM but installed metadata carries a WASM hash\"\n        );\n    }\n    let locked = parse_locked_blake3(capsule, locked_hash)?;\n    let locked_hex = locked.to_hex().to_string();\n    if meta_hash != locked_hex {\n        bail!(\"Distro.lock capsule '{capsule}' hash disagrees with installed metadata\");\n    }\n    let bytes = if let Some(store) = store {\n        let name = astrid_storage::ContentName::new(format!(\"bin/{locked_hex}.wasm\"))?;\n        let descriptor = store\n            .content()\n            .describe(&astrid_storage::StateOwner::System, &name)\n            .map_err(|error| anyhow::anyhow!(error))?\n            .ok_or_else(|| {\n                anyhow::anyhow!(\n                    \"Distro.lock capsule '{capsule}' catalog entry is missing: bin/{locked_hex}.wasm\"\n                )","sourceCodeStart":355,"sourceCodeEnd":391,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/init_grant.rs#L355-L391","documentation":"The reverse consistency check: when the capsule manifest does not declare WASM but the installed metadata nevertheless carries a WASM hash, install state and manifest disagree. Validation refuses to proceed to avoid trusting artifact metadata the manifest never sanctioned.","triggerScenarios":"validate_locked_wasm finds Some(meta_hash) while manifest_declares_wasm(manifest) == false.","commonSituations":"Manifest edited to remove WASM after the capsule was installed with WASM, leftover metadata from a previous WASM-capable version, or a mixed-version install across machines.","solutions":["Reinstall the capsule so metadata matches the current (non-WASM) manifest.","Restore the wasm declaration in the manifest if WASM is actually shipped.","Clear the stale installed metadata (WASM hash) for this capsule."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if !manifest_declares_wasm(&manifest) && installed.wasm_hash.is_some() {\n    return Err(anyhow!(\"stale wasm metadata for {}\", capsule));\n}","typeGuard":null,"tryCatchPattern":"match validate_lock(&lock) {\n    Err(e) if e.to_string().contains(\"does not declare WASM\") => clear_stale_metadata(capsule)?,\n    other => other?,\n}","preventionTips":["Reinstall after removing a wasm declaration from a manifest.","Audit installed metadata when downgrading capsule manifests.","Keep one canonical manifest source of truth per capsule."],"tags":["lockfile","wasm","metadata","state-mismatch"],"backgroundTag":"invalid-state-transition","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"}