astrid-runtime/astrid · error

legacy audit tree crosses a filesystem or mount boundary

Error message

legacy audit tree crosses a filesystem or mount boundary: {path}

What it means

As part of validating the audit tree, each node's st_dev is compared against the root device and each path is checked for being a mountpoint. A subtree on a different filesystem (or a mounted subdirectory) would break the same-device rename and durability assumptions, so validate_audit_tree rejects it with InvalidData.

Solutions

  1. Unmount any filesystems mounted inside the audit tree (see /proc/mounts or `mountpoint <path>`) and re-run
  2. Move the data from the cross-device subtree onto the same filesystem and remove the mount
  3. Retire the tree manually (mv across devices with rsync) if the multi-mount layout must stay

Example fix

// before
/mnt/spare mounted at ~/app/audit/shard-3
// after
umount ~/app/audit/shard-3 && mv /mnt/spare/shard-3/* ~/app/audit/shard-3/
Defensive patterns

Strategy: validation

Validate before calling

use std::os::unix::fs::MetadataExt;
fn tree_on_one_device(root: &std::path::Path) -> std::io::Result<bool> {
    let dev = root.symlink_metadata()?.dev();
    for entry in walkdir_like(root)? {
        if entry.symlink_metadata()?.dev() != dev { return Ok(false); }
    }
    Ok(true)
}

Type guard

fn same_device(a: &std::path::Path, b: &std::path::Path) -> bool {
    use std::os::unix::fs::MetadataExt;
    a.symlink_metadata().map(|m| m.dev()).ok()
        == b.symlink_metadata().map(|m| m.dev()).ok()
}

Try / catch

if let Err(e) = run_migration() {
    if e.kind() == std::io::ErrorKind::InvalidData
        && e.to_string().contains("mount boundary") {
        // unmount or flatten the cross-device subtree, then retry
    } else { return Err(e); }
}

Prevention

When it happens

Trigger: Retiring the legacy audit tree when any directory inside it is a separate mount/bind mount/tmpfs, or when its st_dev differs from the audit root's device.

Common situations: Mounting audit shards onto dedicated volumes for capacity; container bind-mounts inside the audit directory; autofs triggering inside the tree during migration.

Related errors


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

Appendix: source

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

    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)? {
        let child = entry?.path();
        let child_metadata = std::fs::symlink_metadata(&child)?;
        if child_metadata.file_type().is_symlink()
            || audit_tree_device(&child_metadata) != root_device
            || audit_mountpoint(&child)?
        {
            return Err(std::io::Error::new(
                std::io::ErrorKind::InvalidData,
                format!(

View on GitHub (pinned to affd8760f4)