{"record":{"id":"d54d2d70987c235f","repo":"astrid-runtime/astrid","slug":"legacy-principal-home-entry-is-not-a-regular-direc","errorCode":null,"errorMessage":"legacy principal-home entry is not a regular directory: {}","messagePattern":"legacy principal-home entry is not a regular directory: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/legacy_migration_barrier/host_fs.rs","lineNumber":381,"sourceCode":"                io::ErrorKind::InvalidData,\n                format!(\n                    \"legacy principal-home root is not a directory: {}\",\n                    root.display()\n                ),\n            ));\n        },\n        Ok(metadata) => metadata,\n        Err(error) if error.kind() == io::ErrorKind::NotFound => return Ok(false),\n        Err(error) => return Err(error),\n    };\n    let root_device = device_id(&metadata);\n    let mut default_source_present = false;\n    astrid_core::platform_fs::verify_no_redirects(&root)?;\n    for entry in fs::read_dir(&root).map_err(io::Error::other)? {\n        let principal_root = entry.map_err(io::Error::other)?.path();\n        let principal_metadata = fs::symlink_metadata(&principal_root).map_err(io::Error::other)?;\n        if principal_metadata.file_type().is_symlink() || !principal_metadata.is_dir() {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                format!(\n                    \"legacy principal-home entry is not a regular directory: {}\",\n                    principal_root.display()\n                ),\n            ));\n        }\n        if device_id(&principal_metadata) != root_device {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidData,\n                format!(\n                    \"legacy principal-home entry crosses a filesystem boundary: {}\",\n                    principal_root.display()\n                ),\n            ));\n        }\n        astrid_core::platform_fs::verify_no_redirects(&principal_root)?;\n        let local_root = principal_root.join(\".local\");","sourceCodeStart":363,"sourceCodeEnd":399,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/legacy_migration_barrier/host_fs.rs#L363-L399","documentation":"While enumerating the principal home root, preflight_legacy_audit_sources requires every entry to be a regular directory (no symlinks, files, or special files) before treating it as a principal home. A symlinked or non-directory entry could redirect the importer into an unintended subtree, so the scan aborts with InvalidData naming the offending entry.","triggerScenarios":"migrate_legacy_audit finds any entry directly under the home root where symlink_metadata reports is_symlink() || !is_dir() (host_fs.rs:380) — e.g. a symlinked principal directory, a stray file, a socket or device node placed in the home root.","commonSituations":"Symlinking a per-principal directory to another disk; temporary files or sockets dropped into the home root; a partially-created principal directory replaced by a placeholder file.","solutions":["Inspect the reported entry (ls -la) and replace the symlink/file with a real directory if it should be a principal home.","Move unrelated files, sockets, or symlinks out of the home root so it contains only directories.","If the entry is a symlink to real data, replace it with the actual directory (copy or move the target).","Re-run migrate_legacy_audit after the root contains only regular directories."],"exampleFix":"// before\nlrwxrwxrwx principal-7f3a -> /mnt/data/principal-7f3a\n// after\n$ rm principal-7f3a && mv /mnt/data/principal-7f3a . && chmod 700 principal-7f3a","handlingStrategy":"validation","validationCode":"fn scan_home_root(root: &std::path::Path) -> std::io::Result<Vec<std::path::PathBuf>> {\n    let mut bad = Vec::new();\n    for e in std::fs::read_dir(root)? {\n        let p = e?.path();\n        let m = std::fs::symlink_metadata(&p)?;\n        if m.file_type().is_symlink() || !m.is_dir() {\n            bad.push(p);\n        }\n    }\n    Ok(bad) // must be empty before migrating\n}","typeGuard":"fn entry_is_plain_dir(p: &std::path::Path) -> bool {\n    std::fs::symlink_metadata(p).map(|m| !m.file_type().is_symlink() && m.is_dir()).unwrap_or(false)\n}","tryCatchPattern":"match result {\n    Err(e) if e.kind() == std::io::ErrorKind::InvalidData && e.to_string().contains(\"not a regular directory\") => {\n        // clean non-directory entries out of the home root, then retry\n    }\n    other => other?,\n}","preventionTips":["Keep only regular directories directly under the home root.","Run find <home-root> -mindepth 1 -maxdepth 1 ! -type d to spot offending entries first.","Move stray files/sockets elsewhere; never symlink principal directories."],"tags":["filesystem","symlink","migration","validation"],"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"}