astrid-runtime/astrid · critical
durable capsule {id} WASM hash differs between metadata and
Error message
durable capsule {id} WASM hash differs between metadata and archive What it means
During durable capsule identity verification, the BLAKE3 hash of the WASM component actually present in the archive does not equal the wasm_hash recorded in the capsule's metadata record. The library throws this because metadata is supposed to describe exactly the executable bytes being installed; any divergence means one of the two was regenerated or tampered with. Verification is aborted before the package can be read for an owner.
Source
Thrown at crates/astrid-capsule-install/src/storage.rs:312
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");
}
if metadata.wasm_hash.as_deref() != Some(archive_hash.as_str()) {
bail!("durable capsule {id} WASM hash differs between metadata and archive");
}
} else if metadata.wasm_hash.is_some() {
bail!("durable capsule {id} metadata names a hash for a non-WASM component");
}
} else if metadata.wasm_hash.is_some() {
bail!("durable capsule {id} metadata names a component absent from its archive");
}
let mut effective_capabilities = manifest.capabilities.clone();
for component in &manifest.components {
if let Some(capabilities) = &component.capabilities {
effective_capabilities.merge_from(capabilities);
}
}
if !effective_capabilities
.expansions_from(&authority.approved_capabilities)
.is_empty()
{
bail!("durable capsule {id} manifest exceeds its authority receipt");View on GitHub (pinned to affd8760f4)
Solutions
- Republish the capsule so metadata and archive are regenerated together (publish_directory_package recomputes hashes atomically).
- Recompute blake3 of the archive's WASM component and update metadata.wasm_hash to that value.
- If the wrong archive was stored, restore the archive matching the pinned metadata hash from a trusted source.
- Check for interrupted publication/concurrent writers that left metadata and archive out of sync.
Example fix
// before: metadata published with stale hash
CapsuleMeta { wasm_hash: Some("old_blake3_hex".into()), .. }
// after: regenerate metadata from the archive being published
let bytes = std::fs::read("component.wasm")?;
meta.wasm_hash = Some(blake3::hash(&bytes).to_hex().to_string()); Defensive patterns
Strategy: validation
Validate before calling
let bytes = archive_files.get(component_path)?;
let archive_hash = blake3::hash(bytes).to_hex().to_string();
if metadata.wasm_hash.as_deref() != Some(archive_hash.as_str()) {
return Err("metadata wasm_hash does not match archive component");
} Type guard
fn metadata_matches_archive(meta: &CapsuleMeta, archive_hash: &str) -> bool {
meta.wasm_hash.as_deref() == Some(archive_hash)
} Try / catch
match read_verified_durable_package_for_owner(&store, owner, id).await {
Ok(pkg) => pkg,
Err(e) if e.to_string().contains("WASM hash differs between metadata and archive") => {
// republish or restore consistent metadata/archive
},
Err(e) => return Err(e),
} Prevention
- Always republish via publish_directory_package so metadata and archive are generated together.
- Never hand-edit metadata rows after publication.
- Store wasm_hash only as blake3 of the exact bytes shipped in the archive.
When it happens
Trigger: Calling read_verified_durable_package_for_owner (directly or via the mismatch test) when metadata.wasm_hash differs from blake3(archive component bytes) for a component with a .wasm extension, e.g. after the archive was rebuilt while the metadata row kept an old hash.
Common situations: Publishing a rebuilt WASM binary without refreshing CapsuleMeta; hand-editing metadata rows; partial/corrupted writes where the archive landed but metadata update failed; mirroring or importing a capsule from another environment where the binary was recompiled.
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
- installed WASM executable differs from its authority receipt
- Distro.lock capsule '{capsule}' content blob bytes do not ma
- installed WASM integrity check failed: expected BLAKE3 {expe
- durable capsule {id} metadata names a hash for a non-WASM co
- durable capsule {id} metadata names a component absent from
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/ceb1dd8631686514.
Report an issue: GitHub.