{"record":{"id":"61861d6a2fb7ba80","repo":"astrid-runtime/astrid","slug":"legacy-audit-source-has-no-parent","errorCode":null,"errorMessage":"legacy audit source has no parent","messagePattern":"legacy audit source has no parent","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/legacy_migration_barrier/host_fs.rs","lineNumber":456,"sourceCode":"    }\n    Ok(default_source_present)\n}\n\n/// Retire the imported default audit tree through a private staging rename.\n/// The rename makes interrupted deletion resumable, while every pre/post\n/// traversal revalidates no-follow, regular-entry, device, and mount bounds.\n#[cfg(not(unix))]\npub(super) fn retire_legacy_audit_dir(home: &AstridHome, source: &Path) -> io::Result<()> {\n    let retired = home.migrations_dir().join(\"audit-principal-home.retired\");\n    let expected = home.principal_home(&PrincipalId::default()).audit_dir();\n    if source != expected {\n        return Err(io::Error::new(\n            io::ErrorKind::InvalidInput,\n            \"legacy audit retirement source is outside the default principal audit path\",\n        ));\n    }\n    astrid_core::platform_fs::verify_no_redirects(source.parent().ok_or_else(|| {\n        io::Error::new(\n            io::ErrorKind::InvalidInput,\n            \"legacy audit source has no parent\",\n        )\n    })?)?;\n    astrid_core::platform_fs::ensure_private_directory(&home.migrations_dir())?;\n    astrid_core::platform_fs::verify_no_redirects(&home.migrations_dir())?;\n    match fs::symlink_metadata(source) {\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                    \"legacy audit source is not a regular directory: {}\",\n                    source.display()\n                ),\n            ));\n        },\n        Ok(_) => {\n            if fs::symlink_metadata(&retired).is_ok() {","sourceCodeStart":438,"sourceCodeEnd":474,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/legacy_migration_barrier/host_fs.rs#L438-L474","documentation":"During legacy audit-directory retirement (retire_legacy_audit_dir), the code calls source.parent() on the audit source path to verify the parent directory has no redirects (symlinks/redirect files) before renaming. Path::parent() returns None only for a root path (e.g. \"/\") or an empty path, so this error means the source path was so degenerate that it has no parent component. The library throws it as InvalidInput because retirement of a root-level path is never a legitimate legacy audit location.","triggerScenarios":"Calling migrate_legacy_audit with a source path that resolves to \"/\" or an empty path, such that Path::parent() returns None when verifying redirects on the parent before the staging rename.","commonSituations":"Misconfigured legacy home directory pointing at the filesystem root; a home/config resolver that returns an empty string which becomes an empty Path; tests or scripts passing \"/\" as the principal home.","solutions":["Fix the legacy home configuration so the principal audit path is a real subdirectory (e.g. <home>/audit), not \"/\" or an empty path.","Inspect how the source path is constructed and ensure at least one parent component exists before calling migrate_legacy_audit.","Validate the configured home path with Path::parent().is_some() (and that it is not root) before invoking migration."],"exampleFix":"// before\nlet source = Path::new(\"\"); // empty -> parent() is None\nmigrate_legacy_audit(&home, source)?;\n// after\nlet source = home.principal_home(&PrincipalId::default()).audit_dir();\nassert!(source.parent().is_some());\nmigrate_legacy_audit(&home, &source)?;","handlingStrategy":"validation","validationCode":"let source = home.principal_home(&PrincipalId::default()).audit_dir();\nif source.parent().is_none() || source == Path::new(\"/\") {\n    return Err(format!(\"invalid legacy audit source: {}\", source.display()));\n}\nmigrate_legacy_audit(&home, &source)?;","typeGuard":"fn has_parent(p: &Path) -> bool { p.parent().is_some() && p != Path::new(\"/\") }","tryCatchPattern":"match migrate_legacy_audit(&home, &source) {\n    Err(e) if e.to_string().contains(\"has no parent\") => fix_source_path(),\n    other => other?,\n}","preventionTips":["Never configure the legacy home as \"/\" or an empty string.","Validate configured paths with parent().is_some() before migration.","Log the resolved source path before calling migrate_legacy_audit."],"tags":["filesystem","path-validation","migration","io"],"backgroundTag":"invalid-argument-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"}