{"record":{"id":"f5b65b1652c0bb61","repo":"astrid-runtime/astrid","slug":"legacy-audit-source-is-not-a-regular-directory-s","errorCode":null,"errorMessage":"legacy audit source is not a regular directory: {source}","messagePattern":"legacy audit source is not a regular directory: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/lib.rs","lineNumber":4266,"sourceCode":"        .principal_home(&astrid_core::PrincipalId::default())\n        .audit_dir();\n    if source != expected {\n        return Err(std::io::Error::new(\n            std::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        std::io::Error::new(\n            std::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 std::fs::symlink_metadata(source) {\n        Ok(metadata) if metadata.file_type().is_symlink() || !metadata.is_dir() => {\n            return Err(std::io::Error::new(\n                std::io::ErrorKind::InvalidData,\n                format!(\n                    \"legacy audit source is not a regular directory: {}\",\n                    source.display()\n                ),\n            ));\n        },\n        Ok(_) => {\n            if std::fs::symlink_metadata(&retired).is_ok() {\n                return Err(std::io::Error::new(\n                    std::io::ErrorKind::AlreadyExists,\n                    format!(\n                        \"legacy audit retirement is ambiguous: {}\",\n                        retired.display()\n                    ),\n                ));\n            }\n            let root_device = audit_tree_device(&std::fs::symlink_metadata(source)?);","sourceCodeStart":4248,"sourceCodeEnd":4284,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/lib.rs#L4248-L4284","documentation":"The retirement routine requires the audit source to be a real directory. It uses symlink_metadata so symlinks are detected directly: a symlink to a directory, or any non-directory entry (file, fifo, etc.), is rejected with InvalidData because renaming a link would not move the actual audit data safely.","triggerScenarios":"Running legacy audit retirement when the source audit path is a symlink to another directory, a regular file, or otherwise not a directory.","commonSituations":"Audit dir relocated via symlink by an admin; a leftover file occupying the audit path after a failed cleanup; tmpfs-to-disk symlink tricks in containers.","solutions":["Replace the symlink/file at the source path with a real directory containing the audit data, then retry","If it is a symlink, resolve it (mv the target into place) so the migration operates on real data","Inspect with `ls -la <source>` and `stat <source>` to determine what the entry is"],"exampleFix":"// before\naudit -> /var/lib/app/audit   (symlink)\n// after\nrm audit && mv /var/lib/app/audit ./audit   (real directory)","handlingStrategy":"validation","validationCode":"fn source_is_real_dir(p: &std::path::Path) -> bool {\n    std::fs::symlink_metadata(p)\n        .map(|m| !m.file_type().is_symlink() && m.is_dir())\n        .unwrap_or(false)\n}\n// if !source_is_real_dir(&source) { resolve manually first }","typeGuard":"fn is_real_directory(p: &std::path::Path) -> bool {\n    matches!(std::fs::symlink_metadata(p), Ok(m) if m.is_dir() && !m.file_type().is_symlink())\n}","tryCatchPattern":"if let Err(e) = retire_legacy_audit(&home, &source) {\n    if e.kind() == std::io::ErrorKind::InvalidData\n        && e.to_string().contains(\"not a regular directory\") {\n        // materialize the symlink/target into a real dir, then retry\n    } else { return Err(e.into()); }\n}","preventionTips":["Check `ls -la` on the audit path before migrating","Avoid symlink-based audit relocation on upgrade targets","Run a pre-flight script that flags symlinks under the app home"],"tags":["filesystem","symlink","audit","rust"],"backgroundTag":"path-is-not-a-directory","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}