astrid-runtime/astrid · error

durable capsule {id} metadata executable hash differs from a

Error message

durable capsule {id} metadata executable hash differs from authority receipt

What it means

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.

Source

Thrown at crates/astrid-capsule-install/src/storage.rs:292

        bail!("durable capsule {id} manifest digest differs from authority receipt");
    }
    if authority.content_digest != verification.content_digest() {
        bail!("durable capsule {id} content digest differs from authority receipt");
    }
    let expected_imports = crate::wit::version_map_to_strings(&manifest.imports, |definition| {
        definition.version.to_string()
    });
    if metadata.imports != expected_imports {
        bail!("durable capsule {id} imports differ between metadata and archive");
    }
    let expected_exports = crate::wit::version_map_to_strings(&manifest.exports, |definition| {
        definition.version.to_string()
    });
    if metadata.exports != expected_exports {
        bail!("durable capsule {id} exports differ between metadata and archive");
    }
    if authority.wasm_hash_pinned && metadata.wasm_hash != authority.approved_wasm_hash {
        bail!("durable capsule {id} metadata executable hash differs from authority receipt");
    }
    if let Some(component) = manifest.components.first() {
        let Some(relative) = component.path.to_str() else {
            bail!("durable capsule {id} component path is not UTF-8");
        };
        let Some(bytes) = archive_files.get(relative) else {
            bail!("durable capsule {id} component is missing from its archive");
        };
        if Path::new(relative)
            .extension()
            .is_some_and(|extension| extension.eq_ignore_ascii_case("wasm"))
        {
            let archive_hash = blake3::hash(bytes).to_hex().to_string();
            if authority.wasm_hash_pinned
                && authority.approved_wasm_hash.as_deref() != Some(archive_hash.as_str())
            {
                bail!("durable capsule {id} WASM hash differs between authority and archive");
            }

View on GitHub (pinned to affd8760f4)

Solutions

  1. Obtain a new authority receipt whose approved_wasm_hash matches the metadata's wasm_hash (re-approval of the rebuilt component).
  2. Install the exact capsule build the authority approved, so metadata.wasm_hash equals approved_wasm_hash.
  3. If the pin is no longer wanted, have the authority re-issue the receipt without a pinned WASM hash (wasm_hash_pinned = false).
  4. Print both hashes (metadata.wasm_hash vs authority.approved_wasm_hash) to confirm which build is stale.

Example fix

// before: rebuilt wasm, stale receipt
assert_ne!(metadata.wasm_hash, authority.approved_wasm_hash);
// after: refresh the authority receipt for the new build
let authority = request_approval(&new_build); // approved_wasm_hash == metadata.wasm_hash
install_with_authority(&package, &authority);
Defensive patterns

Strategy: validation

Validate before calling

if authority.wasm_hash_pinned && metadata.wasm_hash != authority.approved_wasm_hash {
    return Err(anyhow!("metadata hash {:?} not approved (receipt: {:?})", metadata.wasm_hash, authority.approved_wasm_hash));
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/9de59376083081f4. Report an issue: GitHub.