{"record":{"id":"098c9c23243584c0","repo":"astrid-runtime/astrid","slug":"durable-capsule-contracts-blob-digest-mismatch","errorCode":null,"errorMessage":"durable capsule {} contracts blob digest mismatch","messagePattern":"durable capsule (.+?) contracts blob digest mismatch","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-capsule-install/src/contracts.rs","lineNumber":129,"sourceCode":"                    .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\",\n                summary.id()\n            );\n        };\n        let Some(blob) = package.wit_file(relative) else {\n            bail!(\n                \"durable capsule {} is missing its pinned contracts blob\",\n                summary.id()\n            );\n        };\n        if blake3::hash(blob).to_hex().as_str() != pin {\n            bail!(\n                \"durable capsule {} contracts blob digest mismatch\",\n                summary.id()\n            );\n        }\n        let count = counts.entry(pin.clone()).or_default();\n        *count = count.saturating_add(1);\n    }\n    Ok(counts\n        .into_iter()\n        .max_by(|left, right| left.1.cmp(&right.1).then_with(|| right.0.cmp(&left.0)))\n        .map(|(pin, _)| pin))\n}\n\n/// Refresh the daemon canonical contracts bytes from one durable UID-owned\n/// package registry. This is the storage-backed replacement for the legacy\n/// native fleet scan; it is safe on a fresh home and leaves the canonical\n/// untouched when no retained package contains the shared contracts WIT.\n///","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-capsule-install/src/contracts.rs#L111-L147","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Reinstall the named capsule so the archive content and meta.json pin are regenerated together by the SDK.","If you intentionally changed contracts, rebuild the capsule with the SDK so the pin is recomputed (never hand-edit the blob in place).","Re-publish the durable package and confirm the digest matches via the packaging tool's verify step."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"let blob = package.wit_file(&relative).expect(\"blob present\");\nlet digest = blake3::hash(blob).to_hex();\nassert_eq!(digest.as_str(), pin, \"contracts digest mismatch before scan\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always regenerate meta.json and content together via the SDK build.","Never edit blobs inside a capsule store after publish.","Add a digest-verify step to CI packaging."],"tags":["rust","checksum","blake3","integrity"],"backgroundTag":"checksum-mismatch","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"}