{"record":{"id":"413c87f8ab928f39","repo":"astrid-runtime/astrid","slug":"distro-provenance-receipt-read-back-differs","errorCode":null,"errorMessage":"distro provenance receipt read-back differs","messagePattern":"distro provenance receipt read-back differs","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/principal_distro_migration.rs","lineNumber":306,"sourceCode":"    retire_source(&source, &receipt.source_digest, receipt.source_bytes)\n}\n\nasync fn verify_destination(\n    store: &RuntimePrincipalStore,\n    uid: PrincipalUid,\n    expected_digest: &str,\n) -> io::Result<()> {\n    let scoped = store\n        .principal_control_kv(uid, \"distro\")\n        .map_err(io::Error::other)?;\n    let bytes = scoped\n        .get(KEY)\n        .await\n        .map_err(io::Error::other)?\n        .ok_or_else(|| io::Error::other(\"distro provenance is missing after receipt\"))?;\n    let actual = format!(\"blake3:{}\", blake3::hash(&bytes).to_hex());\n    if actual != expected_digest {\n        return Err(io::Error::new(\n            io::ErrorKind::AlreadyExists,\n            \"distro provenance receipt read-back differs\",\n        ));\n    }\n    Ok(())\n}\n\nfn convert_lock(lock: LegacyLock) -> io::Result<DistroProvenance> {\n    let provenance = DistroProvenance {\n        schema_version: lock.schema_version,\n        distro_id: lock.distro.id,\n        distro_version: lock.distro.version,\n        resolved_at: lock.distro.resolved_at,\n        capsules: lock\n            .capsules\n            .into_iter()\n            .map(|capsule| DistroCapsuleProvenance {\n                name: capsule.name,","sourceCodeStart":288,"sourceCodeEnd":324,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/principal_distro_migration.rs#L288-L324","documentation":"After writing a distro provenance receipt during migration, verify_destination reads the value back from the destination store, hashes it with blake3, and compares to the expected digest. On mismatch it returns AlreadyExists with 'distro provenance receipt read-back differs', indicating the persisted receipt does not match what was intended to be written.","triggerScenarios":"Running migrate_one → verify_destination when the read-back bytes' blake3 hash differs from the expected digest recorded during the write phase.","commonSituations":"Concurrent writers overwrote the receipt mid-migration; storage corruption or a lying/network store returning stale or different bytes; non-atomic store writes; retried migration overwriting the key with different content.","solutions":["Re-run the migration for this entry after quiescing other writers to the store","Verify backend/store integrity; check for stale caches or replication lag in the destination store","Delete the divergent receipt key and re-migrate so it is rewritten atomically","Enable single-writer semantics or locking around migration to prevent concurrent overwrites"],"exampleFix":"// before: concurrent job rewriting the same key\n0 * * * * reconcile-store --all   # races with migration\n// after: pause conflicting jobs during migration\nsystemctl stop reconcile.timer && migrate && systemctl start reconcile.timer","handlingStrategy":"try-catch","validationCode":"let bytes = dest.get(KEY).await?;\nif let Some(b) = bytes {\n    if format!(\"blake3:{}\", blake3::hash(&b).to_hex()) != expected_digest {\n        eprintln!(\"receipt diverges before migration completes\");\n    }\n}","typeGuard":null,"tryCatchPattern":"match migrate_one(entry).await {\n    Err(e) if e.to_string().contains(\"read-back differs\") => {\n        // quiesce writers, delete key, retry migration\n    }\n    other => other?,\n}","preventionTips":["Ensure single-writer access during migration","Back up the destination store before migrating","Verify backend consistency (replication lag, caches)","Make receipt writes atomic and idempotent"],"tags":["checksum","integrity","migration"],"backgroundTag":"checksum-mismatch","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}