{"record":{"id":"03a6dabbd2520e57","repo":"astrid-runtime/astrid","slug":"layout-path-has-no-existing-directory-ancestor","errorCode":null,"errorMessage":"layout path has no existing directory ancestor: {}","messagePattern":"layout path has no existing directory ancestor: (.+?)","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/astrid-core/src/dirs_layout.rs","lineNumber":437,"sourceCode":"}\n\nfn verify_existing_ancestor(path: &Path) -> io::Result<()> {\n    let mut candidate = path;\n    loop {\n        match std::fs::symlink_metadata(candidate) {\n            Ok(metadata) if metadata.file_type().is_symlink() || !metadata.is_dir() => {\n                return Err(io::Error::new(\n                    io::ErrorKind::InvalidData,\n                    format!(\n                        \"layout path is redirected or not a directory: {}\",\n                        candidate.display()\n                    ),\n                ));\n            },\n            Ok(_) => return crate::platform_fs::verify_no_redirects(candidate),\n            Err(error) if error.kind() == io::ErrorKind::NotFound => {\n                candidate = candidate.parent().ok_or_else(|| {\n                    io::Error::new(\n                        io::ErrorKind::InvalidData,\n                        format!(\n                            \"layout path has no existing directory ancestor: {}\",\n                            path.display()\n                        ),\n                    )\n                })?;\n            },\n            Err(error) => return Err(error),\n        }\n    }\n}\n\nfn path_entry_present(path: &Path) -> io::Result<bool> {\n    match std::fs::symlink_metadata(path) {\n        Ok(_) => Ok(true),\n        Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(false),\n        Err(error) => Err(error),","sourceCodeStart":419,"sourceCodeEnd":455,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-core/src/dirs_layout.rs#L419-L455","documentation":"verify_existing_ancestor walks up the parent chain of a home path looking for an existing directory ancestor; if it exhausts the chain (candidate has no parent), it returns InvalidData. In practice this means the Astrid home path is so incomplete that not even a root-adjacent ancestor exists — the path is effectively empty or malformed, so preflight cannot establish a real filesystem anchor.","triggerScenarios":"Calling begin_layout_v2_migration or complete_layout_v2 with a home root whose entire path chain is missing (candidate.parent() eventually returns None, e.g. root or relative path \"\"), or a path so broken no existing ancestor can be found.","commonSituations":"Passing an empty or malformed path as the Astrid home; running in a chroot/container where the home's parent directories were never created; constructing the home path programmatically with a bug that yields \"/\" or an empty PathBuf.","solutions":["Verify the AstridHome root path is absolute, non-empty, and points where you intend","Create the home root with std::fs::create_dir_all before invoking the migration APIs","Fix path-construction bugs that produce empty or root-only paths (e.g. joining onto an empty base)","Run the normal AstridHome::ensure initialization first so the directory skeleton exists before migration preflight runs"],"exampleFix":"// before: empty home path\nlet home = AstridHome::open(Path::new(\"\")).unwrap();\nhome.begin_layout_v2_migration(&target)?; // InvalidData: no existing ancestor\n// after\nlet root = Path::new(\"/var/lib/astrid\");\nstd::fs::create_dir_all(root)?;\nlet home = AstridHome::open(root).unwrap();\nhome.begin_layout_v2_migration(&target)?;","handlingStrategy":"validation","validationCode":"let root = home.root();\nif root.as_os_str().is_empty() || !root.is_absolute() {\n    return Err(anyhow!(\"home root must be a non-empty absolute path\"));\n}\nstd::fs::create_dir_all(root)?;","typeGuard":"fn is_usable_root(p: &Path) -> bool {\n    !p.as_os_str().is_empty() && p.is_absolute()\n}","tryCatchPattern":"match home.begin_layout_v2_migration(&target) {\n    Err(e) if e.to_string().contains(\"no existing directory ancestor\") => {\n        // fix the home path and create the directory tree before retrying\n    },\n    r => r?,\n}","preventionTips":["Validate home paths at config load: absolute and non-empty","Create the root with create_dir_all before any migration call","Check path-construction code for empty-base join bugs","Run AstridHome::ensure before driving migration APIs directly"],"tags":["io","path","migration","invalid-path"],"backgroundTag":"directory-not-found","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"}