{"record":{"id":"ec86dd582506830a","repo":"astrid-runtime/astrid","slug":"layout-migration-receipt-destination-path-does-not","errorCode":null,"errorMessage":"layout migration receipt destination path does not match the live Astrid volume","messagePattern":"layout migration receipt destination path does not match the live Astrid volume","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/astrid-core/src/dirs_layout_records.rs","lineNumber":212,"sourceCode":"pub(super) fn verify_receipt_destination_is_live_path(\n    destination: &LayoutTreeIdentityV1,\n    live_path: &Path,\n) -> io::Result<()> {\n    let parent = live_path.parent().ok_or_else(|| {\n        io::Error::new(\n            io::ErrorKind::InvalidInput,\n            \"live Astrid volume has no parent\",\n        )\n    })?;\n    let file_name = live_path.file_name().ok_or_else(|| {\n        io::Error::new(\n            io::ErrorKind::InvalidInput,\n            \"live Astrid volume has no name\",\n        )\n    })?;\n    let canonical_parent = std::fs::canonicalize(parent)?;\n    if physical_path(destination)? != canonical_parent.join(file_name) {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidData,\n            \"layout migration receipt destination path does not match the live Astrid volume\",\n        ));\n    }\n    verify_receipt_destination_authority(destination)\n}\n\nfn physical_path(destination: &LayoutTreeIdentityV1) -> io::Result<PathBuf> {\n    let bytes = hex::decode(&destination.physical_path_hex)\n        .map_err(|error| io::Error::other(format!(\"decode layout destination path: {error}\")))?;\n    encoded_bytes_to_os_string(bytes).map(PathBuf::from)\n}\n\n#[cfg(unix)]\n#[expect(\n    clippy::unnecessary_wraps,\n    reason = \"the cross-platform receipt decoder has one fallible signature\"\n)]","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-core/src/dirs_layout_records.rs#L194-L230","documentation":"After resolving the live path's canonical parent and file name, verify_receipt_destination_is_live_path compares it against the receipt's physical_path(destination). If the receipt's recorded destination differs from the canonicalized live volume path, this InvalidData error is raised: the migration receipt does not describe the volume currently in use.","triggerScenarios":"Called via retire_verified_legacy_source when canonical_parent.join(file_name) != physical_path(destination) — e.g. the volume was moved/renamed after the receipt was written, or the receipt records a stale or different destination identity.","commonSituations":"Volume file moved to a new mount point or renamed; receipt copied from another machine or volume; a symlinked directory canonicalizes to a different real location than the receipt recorded.","solutions":["Regenerate the layout migration receipt so its destination identity matches the canonical live path.","Restore the volume file to the exact path recorded in the receipt.","Diff the receipt's destination against `readlink -f <live_path>` and reconcile whichever is stale."],"exampleFix":"// before: receipt written for old location\n// destination = /mnt/data/old/volume.bin\n// after: move volume back or rewrite receipt\nstd::fs::rename(\"/mnt/data/new/volume.bin\", \"/mnt/data/old/volume.bin\")?;","handlingStrategy":"validation","validationCode":"let canonical = std::fs::canonicalize(&live_path)?;\nif canonical != /* path from receipt */ {\n    return Err(\"receipt destination does not match live volume; reissue receipt\");\n}","typeGuard":null,"tryCatchPattern":"match retire_verified_legacy_source(...) {\n    Err(e) if e.to_string().contains(\"does not match the live Astrid volume\") => regenerate_receipt_and_retry(),\n    other => other,\n}","preventionTips":["Always regenerate receipts after moving or renaming the volume file.","Compare `readlink -f` of the live path against the receipt before retiring.","Avoid copying receipts between volumes or machines."],"tags":["filesystem","path","migration","io"],"backgroundTag":"invalid-state-transition","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"}