astrid-runtime/astrid · critical

Distro.lock capsule '{capsule}' content blob bytes do not ma

Error message

Distro.lock capsule '{capsule}' content blob bytes do not match hash {locked_hash}

What it means

As the final integrity check, the CLI hashes the actual content blob backing the capsule (from the runtime principal store or the blob path) and requires it to equal the locked blake3 hash. If the bytes differ, the stored artifact is corrupt or substituted and validation bails.

Source

Thrown at crates/astrid-cli/src/commands/init_grant.rs:419

            .map_err(|error| anyhow::anyhow!(error))?
            .ok_or_else(|| {
                anyhow::anyhow!(
                    "Distro.lock capsule '{capsule}' catalog entry has no readable bytes: bin/{locked_hex}.wasm"
                )
            })?
    } else {
        let blob_path = home.bin_dir().join(format!("{locked_hex}.wasm"));
        std::fs::read(&blob_path).with_context(|| {
            format!(
                "Distro.lock capsule '{}' content blob is missing or unreadable at {}",
                capsule,
                blob_path.display()
            )
        })?
    };
    let actual = blake3::hash(&bytes);
    if actual != locked {
        bail!("Distro.lock capsule '{capsule}' content blob bytes do not match hash {locked_hash}");
    }
    Ok(())
}

fn parse_locked_blake3(capsule: &CapsuleId, value: &str) -> anyhow::Result<blake3::Hash> {
    let Some(hex) = value.strip_prefix("blake3:") else {
        bail!("Distro.lock capsule '{capsule}' requires a canonical blake3:<hex> WASM hash");
    };
    let hash = blake3::Hash::from_hex(hex).map_err(|_| {
        anyhow::anyhow!("Distro.lock capsule '{capsule}' has an invalid BLAKE3 hash")
    })?;
    if hex.len() != 64 || hash.to_hex().as_str() != hex {
        bail!("Distro.lock capsule '{capsule}' requires a canonical lowercase BLAKE3 hash");
    }
    Ok(hash)
}

fn manifest_declares_wasm(manifest: &CapsuleManifest) -> bool {

View on GitHub (pinned to affd8760f4)

Solutions

  1. Reinstall the capsule to rewrite the content blob from a trusted source.
  2. Restore the blob bin/{locked_hex}.wasm from a verified artifact so its bytes hash to the locked value.
  3. Regenerate Distro.lock if the new artifact is intentionally the one to trust.
  4. Check storage/disk health if blobs are repeatedly corrupting.
Defensive patterns

Strategy: validation

Validate before calling

let bytes = std::fs::read(&blob_path)?;
let actual = blake3::hash(&bytes);
if actual.to_hex().as_str() != locked_hex {
    return Err(anyhow!("blob corruption for {}", capsule));
}

Try / catch

if let Err(e) = validate_lock(&lock) {
    if e.to_string().contains("bytes do not match hash") {
        restore_blob_from_trusted_source(capsule).await?;
    } else { return Err(e.into()); }
}

Prevention

When it happens

Trigger: validate_locked_wasm loads the blob bytes, computes blake3::hash(&bytes), and the result != locked hash parsed from the lockfile.

Common situations: Corrupted or truncated blob in the content store, blob overwritten by another build, disk corruption, or content-addressed file bin/{hex}.wasm replaced manually.

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/1a543fc97c771ad3. Report an issue: GitHub.