{"record":{"id":"a43cf4e078b7a937","repo":"astrid-runtime/astrid","slug":"layout-migration-destination-is-redirected-or-not","errorCode":null,"errorMessage":"layout migration destination is redirected or not a regular file: {}","messagePattern":"layout migration destination is redirected or not a regular file: (.+?)","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/astrid-core/src/dirs_layout_records.rs","lineNumber":183,"sourceCode":"    if actual != expected {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidData,\n            format!(\n                \"layout migration record is not canonical: {}\",\n                path.display()\n            ),\n        ));\n    }\n    Ok(parsed)\n}\n\npub(super) fn verify_receipt_destination_authority(\n    destination: &LayoutTreeIdentityV1,\n) -> io::Result<()> {\n    let path = physical_path(destination)?;\n    let metadata = std::fs::symlink_metadata(&path)?;\n    if metadata.file_type().is_symlink() || !metadata.is_file() {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidData,\n            format!(\n                \"layout migration destination is redirected or not a regular file: {}\",\n                path.display()\n            ),\n        ));\n    }\n    crate::platform_fs::verify_no_redirects(&path)\n}\n\npub(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\",","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-core/src/dirs_layout_records.rs#L165-L201","documentation":"verify_receipt_destination_authority validates that the migration receipt's recorded destination is an authoritative, unredirected regular file. It reads symlink_metadata on the destination's physical path and rejects it if the entry is a symlink or not a plain file. This guards against a receipt pointing at a path that an attacker or misconfiguration has redirected (e.g. symlink swap) or that was replaced by a directory or other non-file entry.","triggerScenarios":"Called from verify_receipt_destination_is_live_path (itself called by retire_verified_legacy_source) whenever the path returned by physical_path(destination) is a symlink, directory, FIFO, socket, or any non-regular file when checked via std::fs::symlink_metadata.","commonSituations":"The Astrid volume path was replaced by a symlink (e.g. to a mount point or tmpfs alias) after the receipt was written; the destination file was deleted and a directory created with the same name; a backup/restore tool replaced the volume file with a symlink.","solutions":["Remove the symlink at the destination path and replace it with the real regular file the receipt points to.","Re-create or re-issue the layout migration receipt so its LayoutTreeIdentityV1 matches the current real on-disk path.","Inspect the path with `ls -la` / `stat` to see what replaced the regular file and restore it (e.g. from the migration source)."],"exampleFix":"// before: destination replaced by symlink\nln -s /mnt/other/volume /path/to/astrid-volume\n// after: real regular file at the destination\nrm /path/to/astrid-volume\ncp /mnt/other/volume /path/to/astrid-volume   # then re-run retirement","handlingStrategy":"validation","validationCode":"let md = std::fs::symlink_metadata(&dest_path)?;\nif md.file_type().is_symlink() || !md.is_file() {\n    return Err(\"receipt destination is not an unredirected regular file\");\n}","typeGuard":null,"tryCatchPattern":"match retire_verified_legacy_source(...) {\n    Err(e) if e.to_string().contains(\"redirected or not a regular file\") => restore_real_destination_file(),\n    Err(e) => return Err(e),\n    Ok(()) => {},\n}","preventionTips":["Never place symlinks on Astrid volume paths; mount real filesystems instead.","Run `find <dir> -type l` periodically to detect redirected paths.","Re-issue receipts after any path/restore operation."],"tags":["filesystem","symlink","migration","io"],"backgroundTag":"incompatible-source-type","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"}