astrid-runtime/astrid · error

durable capsule {} contracts blob digest mismatch

Error message

durable capsule {} contracts blob digest mismatch

What it means

The pinned blob was found, but its actual BLAKE3 digest does not equal the pin recorded in meta.json. durable_contracts_pin treats this as corruption/tampering and aborts the fleet scan rather than counting a capsule whose contracts content doesn't match its declared pin.

Source

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

                    .file_name()
                    .and_then(|name| name.to_str())
                    == Some(CONTRACTS_WIT_BASENAME)
            })
            .min()
        else {
            bail!(
                "durable capsule {} is missing its pinned contracts blob",
                summary.id()
            );
        };
        let Some(blob) = package.wit_file(relative) else {
            bail!(
                "durable capsule {} is missing its pinned contracts blob",
                summary.id()
            );
        };
        if blake3::hash(blob).to_hex().as_str() != pin {
            bail!(
                "durable capsule {} contracts blob digest mismatch",
                summary.id()
            );
        }
        let count = counts.entry(pin.clone()).or_default();
        *count = count.saturating_add(1);
    }
    Ok(counts
        .into_iter()
        .max_by(|left, right| left.1.cmp(&right.1).then_with(|| right.0.cmp(&left.0)))
        .map(|(pin, _)| pin))
}

/// Refresh the daemon canonical contracts bytes from one durable UID-owned
/// package registry. This is the storage-backed replacement for the legacy
/// native fleet scan; it is safe on a fresh home and leaves the canonical
/// untouched when no retained package contains the shared contracts WIT.
///

View on GitHub (pinned to affd8760f4)

Solutions

  1. Reinstall the named capsule so the archive content and meta.json pin are regenerated together by the SDK.
  2. If you intentionally changed contracts, rebuild the capsule with the SDK so the pin is recomputed (never hand-edit the blob in place).
  3. Re-publish the durable package and confirm the digest matches via the packaging tool's verify step.
Defensive patterns

Strategy: validation

Validate before calling

let blob = package.wit_file(&relative).expect("blob present");
let digest = blake3::hash(blob).to_hex();
assert_eq!(digest.as_str(), pin, "contracts digest mismatch before scan");

Prevention

When it happens

Trigger: Calling durable_contracts_pin / refresh_canonical_contracts_from_registry when the astrid-contracts.wit bytes inside a capsule's durable package hash to something other than the wit_files pin: blob swapped after metadata was written, archive recompressed/rewritten without updating meta.json, or bit corruption.

Common situations: Post-hoc editing of a capsule's contracts WIT file in the store; an interrupted write that corrupted the blob; a packager that writes metadata before finalizing content.

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/098c9c23243584c0. Report an issue: GitHub.