{"record":{"id":"3c579314a3a1fb5e","repo":"astrid-runtime/astrid","slug":"live-astrid-volume-has-no-parent","errorCode":null,"errorMessage":"live Astrid volume has no parent","messagePattern":"live Astrid volume has no parent","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/astrid-core/src/dirs_layout_records.rs","lineNumber":199,"sourceCode":"    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\",\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)","sourceCodeStart":181,"sourceCodeEnd":217,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-core/src/dirs_layout_records.rs#L181-L217","documentation":"verify_receipt_destination_is_live_path needs the parent directory of the live Astrid volume path to canonicalize and compare it against the receipt's recorded destination. If the live path has no parent component (i.e. it is a bare root path like \"/\" with no file-name portion for its parent lookup), this io::Error with InvalidInput is raised. This is essentially a degenerate-path guard.","triggerScenarios":"verify_receipt_destination_is_live_path is called (via retire_verified_legacy_source) with live_path == \"/\" or another path whose Path::parent() returns None, so parent extraction fails before file_name extraction.","commonSituations":"Misconfigured volume path pointing at the filesystem root instead of a file inside a directory; an env var or config value like ASTRID_VOLUME=\"/\" passed through unchanged; programmatic construction of the live path that dropped the file component.","solutions":["Fix the configured live volume path so it points at a file inside a directory, not the filesystem root.","Check the config/env value that supplies the live path and ensure it includes a parent directory and file name.","Log/print the live path before calling retire_verified_legacy_source to confirm it is non-root."],"exampleFix":"// before\nlet live_path = Path::new(\"/\");\n// after\nlet live_path = Path::new(\"/var/lib/astrid/volume.bin\");","handlingStrategy":"validation","validationCode":"let live = Path::new(&volume_config);\nif live.parent().is_none() || live == Path::new(\"/\") {\n    return Err(\"live volume path must be a file inside a directory, not the root\");\n}","typeGuard":null,"tryCatchPattern":"match retire_verified_legacy_source(...) {\n    Err(e) if e.kind() == std::io::ErrorKind::InvalidInput && e.to_string().contains(\"no parent\") => fix_volume_config(),\n    other => other,\n}","preventionTips":["Validate configured volume paths point to files, never \"/\".","Reject root paths at config-load time.","Log the resolved live path before retirement."],"tags":["filesystem","path","configuration","io"],"backgroundTag":"invalid-config-value","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"}