astrid-runtime/astrid · error
legacy audit source is not a regular directory
Error message
legacy audit source is not a regular directory: {source} What it means
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.
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
Example fix
// before audit -> /var/lib/app/audit (symlink) // after rm audit && mv /var/lib/app/audit ./audit (real directory)
Defensive patterns
Strategy: validation
Validate before calling
fn source_is_real_dir(p: &std::path::Path) -> bool {
std::fs::symlink_metadata(p)
.map(|m| !m.file_type().is_symlink() && m.is_dir())
.unwrap_or(false)
}
// if !source_is_real_dir(&source) { resolve manually first } Type guard
fn is_real_directory(p: &std::path::Path) -> bool {
matches!(std::fs::symlink_metadata(p), Ok(m) if m.is_dir() && !m.file_type().is_symlink())
} Try / catch
if let Err(e) = retire_legacy_audit(&home, &source) {
if e.kind() == std::io::ErrorKind::InvalidData
&& e.to_string().contains("not a regular directory") {
// materialize the symlink/target into a real dir, then retry
} else { return Err(e.into()); }
} Prevention
- 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
When it happens
Trigger: Running legacy audit retirement when the source audit path is a symlink to another directory, a regular file, or otherwise not a directory.
Common situations: 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.
Related errors
- legacy audit tree is redirected or not a directory
- capsule path escaped source root
- directory symlink not allowed in capsule source tree…
- inspect projected file
- legacy audit tree crosses a filesystem or mount boundary
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/f5b65b1652c0bb61.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-kernel/src/lib.rs:4266
.principal_home(&astrid_core::PrincipalId::default())
.audit_dir();
if source != expected {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"legacy audit retirement source is outside the default principal audit path",
));
}
astrid_core::platform_fs::verify_no_redirects(source.parent().ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"legacy audit source has no parent",
)
})?)?;
astrid_core::platform_fs::ensure_private_directory(&home.migrations_dir())?;
astrid_core::platform_fs::verify_no_redirects(&home.migrations_dir())?;
match std::fs::symlink_metadata(source) {
Ok(metadata) if metadata.file_type().is_symlink() || !metadata.is_dir() => {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!(
"legacy audit source is not a regular directory: {}",
source.display()
),
));
},
Ok(_) => {
if std::fs::symlink_metadata(&retired).is_ok() {
return Err(std::io::Error::new(
std::io::ErrorKind::AlreadyExists,
format!(
"legacy audit retirement is ambiguous: {}",
retired.display()
),
));
}
let root_device = audit_tree_device(&std::fs::symlink_metadata(source)?);View on GitHub (pinned to affd8760f4)