astrid-runtime/astrid · error

legacy principal-home entry crosses a filesystem boundary: {

Error message

legacy principal-home entry crosses a filesystem boundary: {}

What it means

preflight_legacy_audit_sources compares each principal-home entry's device id (st_dev) against the home root's device and aborts if they differ. A principal directory living on another filesystem cannot be safely covered by the same migration traversal/retirement assumptions, so the migration stops with InvalidData before opening any audit source.

Source

Thrown at crates/astrid-kernel/src/legacy_migration_barrier/host_fs.rs:390

        Err(error) => return Err(error),
    };
    let root_device = device_id(&metadata);
    let mut default_source_present = false;
    astrid_core::platform_fs::verify_no_redirects(&root)?;
    for entry in fs::read_dir(&root).map_err(io::Error::other)? {
        let principal_root = entry.map_err(io::Error::other)?.path();
        let principal_metadata = fs::symlink_metadata(&principal_root).map_err(io::Error::other)?;
        if principal_metadata.file_type().is_symlink() || !principal_metadata.is_dir() {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                format!(
                    "legacy principal-home entry is not a regular directory: {}",
                    principal_root.display()
                ),
            ));
        }
        if device_id(&principal_metadata) != root_device {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                format!(
                    "legacy principal-home entry crosses a filesystem boundary: {}",
                    principal_root.display()
                ),
            ));
        }
        astrid_core::platform_fs::verify_no_redirects(&principal_root)?;
        let local_root = principal_root.join(".local");
        match fs::symlink_metadata(&local_root) {
            Ok(metadata) if metadata.file_type().is_symlink() || !metadata.is_dir() => {
                return Err(io::Error::new(
                    io::ErrorKind::InvalidData,
                    format!(
                        "legacy principal .local path is not a directory: {}",
                        local_root.display()
                    ),
                ));

View on GitHub (pinned to affd8760f4)

Solutions

  1. Unmount the separate filesystem mounted at the reported principal path (umount) and re-run the migration.
  2. Move the principal's data onto the same filesystem as the home root and remove the mount.
  3. Keep the extra mount, but relocate it outside the principal home root tree.
  4. If using containers, stop bind-mounting volumes at per-principal paths inside the home root during migration.

Example fix

// before
/dev/sdb1 on /home/u/principal-7f3a type ext4
// after
$ umount /home/u/principal-7f3a && mv /mnt/sdb1-data/principal-7f3a /home/u/
Defensive patterns

Strategy: validation

Validate before calling

use std::os::unix::fs::MetadataExt;
fn principals_on_root_device(root: &std::path::Path) -> std::io::Result<Vec<std::path::PathBuf>> {
    let root_dev = std::fs::symlink_metadata(root)?.dev();
    let mut bad = Vec::new();
    for e in std::fs::read_dir(root)? {
        let p = e?.path();
        if std::fs::symlink_metadata(&p)?.dev() != root_dev {
            bad.push(p);
        }
    }
    Ok(bad) // must be empty before migrating
}

Type guard

fn on_same_fs(root_dev: u64, p: &std::path::Path) -> bool {
    std::os::unix::fs::MetadataExt::dev(&std::fs::symlink_metadata(p).ok()?) == root_dev
}

Try / catch

match result {
    Err(e) if e.kind() == std::io::ErrorKind::InvalidData && e.to_string().contains("filesystem boundary") => {
        // unmount or relocate the reported principal dir, then retry
    }
    other => other?,
}

Prevention

When it happens

Trigger: migrate_legacy_audit with a principal directory under the home root that resides on a different mounted filesystem than the home root itself (device_id(&principal_metadata) != root_device, host_fs.rs:389) — e.g. a separate mount or bind mount for one principal.

Common situations: Mounting a dedicated disk/NFS share for one user's data under the home root; containers bind-mounting a volume at a principal directory path; encrypted-home setups mounting at a subdirectory.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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