{"record":{"id":"694777c5e2294018","repo":"astrid-runtime/astrid","slug":"durable-capsule-has-malformed-contracts-pin","errorCode":null,"errorMessage":"durable capsule {} has malformed contracts pin","messagePattern":"durable capsule (.+?) has malformed contracts pin","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-capsule-install/src/contracts.rs","lineNumber":100,"sourceCode":"pub fn durable_contracts_pin(\n    store: &RuntimePrincipalStore,\n    owner: &StateOwner,\n) -> anyhow::Result<Option<String>> {\n    let registry = store.capsules();\n    let mut counts = std::collections::BTreeMap::<String, usize>::new();\n    for summary in registry.list(owner)? {\n        let Some(package) = read_verified_durable_package_for_owner(store, owner, summary.id())?\n        else {\n            bail!(\n                \"capsule {} disappeared during durable contracts scan\",\n                summary.id()\n            );\n        };\n        let Some(pin) = contracts_pin(&package.metadata().wit_files) else {\n            continue;\n        };\n        if !is_blake3_pin(pin) {\n            bail!(\n                \"durable capsule {} has malformed contracts pin\",\n                summary.id()\n            );\n        }\n        let Some(relative) = package\n            .metadata()\n            .wit_files\n            .keys()\n            .filter(|relative| {\n                Path::new(relative.as_str())\n                    .file_name()\n                    .and_then(|name| name.to_str())\n                    == Some(CONTRACTS_WIT_BASENAME)\n            })\n            .min()\n        else {\n            bail!(\n                \"durable capsule {} is missing its pinned contracts blob\",","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-capsule-install/src/contracts.rs#L82-L118","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","Recompute the pin: `blake3 hash` the vendored astrid-contracts.wit and write that hex into meta.json's wit_files entry for the file.","If the metadata is unrecoverable, remove and re-publish the capsule to the registry, then re-run the refresh."],"exampleFix":"// before (meta.json wit_files)\n\"deps/astrid-contracts/astrid-contracts.wit\": \"abc123\"\n// after\n\"deps/astrid-contracts/astrid-contracts.wit\": \"<full 64-char blake3 hex>\"","handlingStrategy":"validation","validationCode":"fn is_blake3_pin(pin: &str) -> bool {\n    pin.len() == 64 && pin.chars().all(|c| c.is_ascii_hexdigit() && !c.is_ascii_uppercase())\n}\n// before calling the scan, verify each capsule's meta.json pin:\n// assert!(is_blake3_pin(pin));","typeGuard":"fn valid_pin(wit_files: &HashMap<String, String>) -> Option<&String> {\n    contracts_pin(wit_files).filter(|p| is_blake3_pin(p))\n}","tryCatchPattern":null,"preventionTips":["Never hand-edit a durable package's meta.json; always rebuild with the SDK.","Standardize on BLAKE3-hex for all pins and validate at write time.","Re-publish rather than migrating capsules across hash formats."],"tags":["rust","validation","blake3","metadata"],"backgroundTag":"invalid-argument-format","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}