astrid-runtime/astrid · critical

durable capsule {id} manifest digest differs from authority

Error message

durable capsule {id} manifest digest differs from authority receipt

What it means

This error fires when digest_manifest(manifest_bytes) does not equal the manifest_digest recorded in the authority receipt. The authority receipt pins the exact bytes of the manifest it approved; a different digest means the manifest on disk was modified after signing, or the receipt belongs to a different manifest. The library refuses to load such a capsule because the approved manifest cannot be trusted.

Source

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

    manifest_bytes: &[u8],
    verification: &ArtifactVerification,
    archive_files: &std::collections::BTreeMap<String, Vec<u8>>,
) -> anyhow::Result<()> {
    if authority.schema_version != 1 {
        bail!(
            "durable capsule {id} has unsupported authority schema {}",
            authority.schema_version
        );
    }
    if authority.capsule_id != id || manifest.package.name != id {
        bail!("durable capsule {id} identity differs across archive and authority");
    }
    if authority.version != manifest.package.version || metadata.version != authority.version {
        bail!("durable capsule {id} version differs across package records");
    }
    let manifest_digest = crate::authority::digest_manifest(manifest_bytes);
    if authority.manifest_digest != manifest_digest {
        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");

View on GitHub (pinned to affd8760f4)

Solutions

  1. Re-run the authority approval step to re-sign the current manifest bytes and update the receipt's manifest_digest.
  2. Restore the original signed manifest bytes that match the receipt (e.g. from the publish artifact or VCS).
  3. Reinstall the capsule from the originally published archive instead of a locally modified one.
  4. Ensure the build pipeline does not rewrite the manifest between approval and install.

Example fix

// before: editing the manifest after approval
// manifest.capabilities.network added by hand -> digest differs from receipt
// after: re-approve so the receipt covers the new bytes
let manifest_bytes = serialize_manifest(&edited_manifest)?;
let receipt = authority.approve(&manifest_bytes)?; // refreshes manifest_digest
store.write_authority(owner, id, &receipt)?;
Defensive patterns

Strategy: validation

Validate before calling

let digest = crate::authority::digest_manifest(&manifest_bytes);
if digest != authority.manifest_digest {
    // re-approve or restore original manifest before loading
}

Type guard

fn manifest_is_approved(bytes: &[u8], a: &InstalledAuthority) -> bool {
    crate::authority::digest_manifest(bytes) == a.manifest_digest
}

Try / catch

match store.read_verified_durable_package_for_owner(owner, id) {
    Ok(pkg) => pkg,
    Err(e) if e.to_string().contains("manifest digest differs from authority receipt") => {
        // restore signed manifest or re-run authority approval
        authority.approve(&manifest_bytes)?;
        store.read_verified_durable_package_for_owner(owner, id)?
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: read_verified_durable_package_for_owner loads an archive whose manifest bytes hash to something other than InstalledAuthority.manifest_digest — typically after editing CapsuleManifest fields (name, version, imports, exports, capabilities) without re-running the authority approval step.

Common situations: Hand-editing capsule.toml/manifest to tweak dependencies or permissions post-install; a build pipeline regenerating the manifest with different formatting/field order after approval; replaying an old authority receipt over a newly built archive.

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/50ff7054920846bb. Report an issue: GitHub.