astrid-runtime/astrid · error

durable capsule {id} metadata names a hash for a non-WASM co

Error message

durable capsule {id} metadata names a hash for a non-WASM component

What it means

verify_package_identity found metadata.wasm_hash set while the capsule's component file does not have a .wasm extension, so there is no WASM artifact the recorded hash could describe. The library rejects this because wasm_hash is only meaningful for a WASM component; a populated value next to a non-WASM component indicates inconsistent metadata. Read of the verified durable package is refused.

Source

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

        };
        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");
    }
    match verification {
        ArtifactVerification::Signed(provenance) => {

View on GitHub (pinned to affd8760f4)

Solutions

  1. Clear metadata.wasm_hash (set to None) for capsules whose component is not a .wasm file.
  2. Restore the .wasm component if the capsule was actually meant to ship WASM.
  3. Fix the publishing tool so it only sets wasm_hash when the component path ends in .wasm.
  4. Republish the capsule with consistent manifest + metadata.

Example fix

// before
meta.wasm_hash = Some(hash_of_nonwasm_component);
// after
if component.path.extension().is_some_and(|e| e.eq_ignore_ascii_case("wasm")) {
    meta.wasm_hash = Some(hash);
} else {
    meta.wasm_hash = None;
}
Defensive patterns

Strategy: validation

Validate before calling

if meta.wasm_hash.is_some()
    && !component.path.extension().is_some_and(|e| e.eq_ignore_ascii_case("wasm"))
{
    return Err("wasm_hash set but component is not a .wasm file");
}

Type guard

fn is_wasm_component(p: &std::path::Path) -> bool {
    p.extension().is_some_and(|e| e.eq_ignore_ascii_case("wasm"))
}

Try / catch

match read_verified_durable_package_for_owner(&store, owner, id).await {
    Ok(pkg) => pkg,
    Err(e) if e.to_string().contains("hash for a non-WASM component") => {
        // clear metadata.wasm_hash or restore the wasm component
    },
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: read_verified_durable_package_for_owner on a capsule whose manifest component path lacks a .wasm extension (or component.path isn't UTF-8-safe with .wasm) while CapsuleMeta.wasm_hash is Some(_).

Common situations: Metadata written for an earlier WASM build that was later replaced by a non-WASM component (e.g. a WIT-only or data component); copy-pasting metadata between capsules; a tool that unconditionally stamps wasm_hash.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — 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/358c2ccd128780f1. Report an issue: GitHub.