astrid-runtime/astrid · error

legacy audit tree is redirected or not a directory

Error message

legacy audit tree is redirected or not a directory: {path}

What it means

validate_audit_tree recursively re-checks every node of the audit tree before and after the retirement rename. Any node that is a symlink or not a directory means part of the tree could redirect writes outside the validated device, so the whole tree is rejected with InvalidData.

Solutions

  1. Find the offending node (walk the tree with `find <path> -type l -o ! -type d`) and replace the symlink/file with a real directory
  2. Materialize symlinked subdirectories back into the tree (mv the target content in place)
  3. Repair or recreate the audit tree from logs if it is structurally corrupted

Example fix

// before
audit/shard-3 -> /mnt/spare/shard-3   (symlink inside tree)
// after
rm audit/shard-3 && mv /mnt/spare/shard-3 audit/shard-3
Defensive patterns

Strategy: validation

Validate before calling

fn tree_has_no_symlinks(root: &std::path::Path) -> std::io::Result<bool> {
    for entry in walkdir_like(root)? {
        let m = std::fs::symlink_metadata(&entry)?;
        if m.file_type().is_symlink() { return Ok(false); }
    }
    Ok(true)
}

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) = run_migration() {
    if e.kind() == std::io::ErrorKind::InvalidData
        && e.to_string().contains("redirected or not a directory") {
        // locate offending node from the message path, materialize it, retry
    } else { return Err(e); }
}

Prevention

When it happens

Trigger: Retiring the legacy audit tree when any subdirectory inside it is a symlink, or when a file exists where a directory is expected in the audit hierarchy.

Common situations: Admins symlinking a large audit subdirectory to another disk; corrupted/partial audit trees after crashes; backup-restore tools replacing directories with links.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/b3da9caa20ac300f. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-kernel/src/lib.rs:4322

            }
        },
        Err(error) => return Err(error),
    }
    Ok(())
}

#[cfg(unix)]
fn audit_tree_device(metadata: &std::fs::Metadata) -> u64 {
    use std::os::unix::fs::MetadataExt as _;

    metadata.dev()
}

#[cfg(unix)]
fn validate_audit_tree(path: &Path, root_device: u64) -> std::io::Result<()> {
    let metadata = std::fs::symlink_metadata(path)?;
    if metadata.file_type().is_symlink() || !metadata.is_dir() {
        return Err(std::io::Error::new(
            std::io::ErrorKind::InvalidData,
            format!(
                "legacy audit tree is redirected or not a directory: {}",
                path.display()
            ),
        ));
    }
    if audit_tree_device(&metadata) != root_device || audit_mountpoint(path)? {
        return Err(std::io::Error::new(
            std::io::ErrorKind::InvalidData,
            format!(
                "legacy audit tree crosses a filesystem or mount boundary: {}",
                path.display()
            ),
        ));
    }
    astrid_core::platform_fs::verify_no_redirects(path)?;
    for entry in std::fs::read_dir(path)? {

View on GitHub (pinned to affd8760f4)