astrid-runtime/astrid · error

durable capsule {} has malformed contracts pin

Error message

durable capsule {} has malformed contracts pin

What it means

durable_contracts_pin computes the plurality (fleet-wide majority) BLAKE3 contracts pin by scanning every capsule in the owner's durable registry. Each capsule's meta.json `wit_files` map must carry a well-formed BLAKE3-hex pin for astrid-contracts.wit. When the stored pin string is not valid BLAKE3 hex (e.g. truncated, wrong length, non-hex characters), the scan refuses to continue rather than computing a majority over untrustworthy pins.

Source

Thrown at crates/astrid-capsule-install/src/contracts.rs:100

pub fn durable_contracts_pin(
    store: &RuntimePrincipalStore,
    owner: &StateOwner,
) -> anyhow::Result<Option<String>> {
    let registry = store.capsules();
    let mut counts = std::collections::BTreeMap::<String, usize>::new();
    for summary in registry.list(owner)? {
        let Some(package) = read_verified_durable_package_for_owner(store, owner, summary.id())?
        else {
            bail!(
                "capsule {} disappeared during durable contracts scan",
                summary.id()
            );
        };
        let Some(pin) = contracts_pin(&package.metadata().wit_files) else {
            continue;
        };
        if !is_blake3_pin(pin) {
            bail!(
                "durable capsule {} has malformed contracts pin",
                summary.id()
            );
        }
        let Some(relative) = package
            .metadata()
            .wit_files
            .keys()
            .filter(|relative| {
                Path::new(relative.as_str())
                    .file_name()
                    .and_then(|name| name.to_str())
                    == Some(CONTRACTS_WIT_BASENAME)
            })
            .min()
        else {
            bail!(
                "durable capsule {} is missing its pinned contracts blob",

View on GitHub (pinned to affd8760f4)

Solutions

  1. Identify the offending capsule id from the message and rebuild/reinstall it with the current SDK so meta.json's wit_files pin is a proper BLAKE3 hex digest.
  2. Recompute the pin: `blake3 hash` the vendored astrid-contracts.wit and write that hex into meta.json's wit_files entry for the file.
  3. If the metadata is unrecoverable, remove and re-publish the capsule to the registry, then re-run the refresh.

Example fix

// before (meta.json wit_files)
"deps/astrid-contracts/astrid-contracts.wit": "abc123"
// after
"deps/astrid-contracts/astrid-contracts.wit": "<full 64-char blake3 hex>"
Defensive patterns

Strategy: validation

Validate before calling

fn is_blake3_pin(pin: &str) -> bool {
    pin.len() == 64 && pin.chars().all(|c| c.is_ascii_hexdigit() && !c.is_ascii_uppercase())
}
// before calling the scan, verify each capsule's meta.json pin:
// assert!(is_blake3_pin(pin));

Type guard

fn valid_pin(wit_files: &HashMap<String, String>) -> Option<&String> {
    contracts_pin(wit_files).filter(|p| is_blake3_pin(p))
}

Prevention

When it happens

Trigger: Calling durable_contracts_pin (directly or via refresh_canonical_contracts_from_registry) when any registered capsule's meta.json contains an entry for astrid-contracts.wit whose value is not a valid BLAKE3 hex digest — hand-edited meta.json, a writer that stored a short-hash or sha256 instead of blake3, or corrupt/truncated metadata.

Common situations: Hand-editing or post-processing a durable package's meta.json; migrating capsules built by an older SDK that recorded a different hash format; metadata corruption from an interrupted write or manual copying of the store between machines.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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