astrid-runtime/astrid · error

legacy source crosses a device boundary: {}

Error message

legacy source crosses a device boundary: {}

What it means

validate_source_path requires the source file to live on the same device as its parent directory (compared via device_id, i.e. st_dev). If they differ — meaning the entry sits on a different filesystem than its parent — the migration barrier treats it as crossing a device boundary and returns InvalidData, since safe in-place migration assumptions break across filesystems.

Source

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

    if metadata.file_type().is_symlink() || !metadata.is_file() {
        return Err(io::Error::new(
            io::ErrorKind::InvalidData,
            format!("legacy source is not a regular file: {}", path.display()),
        ));
    }
    astrid_core::platform_fs::verify_no_redirects(path)?;
    validate_private_entry(path, &metadata)?;
    if active_mountpoint(path)? {
        return Err(io::Error::new(
            io::ErrorKind::InvalidData,
            format!("legacy source is an active mount: {}", path.display()),
        ));
    }
    if let Some(parent) = path.parent()
        && let Ok(parent_metadata) = fs::symlink_metadata(parent)
        && device_id(&parent_metadata) != device_id(&metadata)
    {
        return Err(io::Error::new(
            io::ErrorKind::InvalidData,
            format!(
                "legacy source crosses a device boundary: {}",
                path.display()
            ),
        ));
    }
    Ok(())
}

fn snapshot_dir(
    root: &Path,
    dir: &Path,
    device: u64,
    access: SourceAccess,
    hasher: &mut blake3::Hasher,
    identity: &mut SourceInventory,
) -> io::Result<()> {

View on GitHub (pinned to affd8760f4)

Solutions

  1. Move or copy the file onto the same filesystem as its parent directory, then validate the copy.
  2. Remove the cross-device bind mount so the path is a normal file on the parent filesystem.
  3. Choose a source location entirely within one filesystem.

Example fix

// before
let src = Path::new("/var/astrid/state.lock"); // tmpfs mounted at /var/astrid, parent on ext4
validate_source_path(src)?;

// after
let src = Path::new("/var/lib/astrid/state.lock"); // same filesystem as its parent
validate_source_path(src)?;
Defensive patterns

Strategy: validation

Validate before calling

fn same_device_as_parent(path: &std::path::Path) -> std::io::Result<bool> {
    use std::os::unix::fs::MetadataExt;
    let md = std::fs::symlink_metadata(path)?;
    let parent = path.parent().ok_or_else(|| std::io::Error::other("no parent"))?;
    let pmd = std::fs::symlink_metadata(parent)?;
    Ok(md.dev() == pmd.dev())
}
assert!(same_device_as_parent(&src)?, "source crosses a device boundary");

Type guard

fn same_device(path: &std::path::Path) -> bool {
    use std::os::unix::fs::MetadataExt;
    match (std::fs::symlink_metadata(path), path.parent().and_then(|p| std::fs::symlink_metadata(p).ok())) {
        (Ok(m), Some(p)) => m.dev() == p.dev(),
        _ => false,
    }
}

Try / catch

if let Err(e) = validate_source_path(&src) {
    if e.to_string().contains("device boundary") {
        let copy = std::path::Path::new("/var/lib/astrid/src-copy");
        std::fs::copy(&src, copy)?;
        return validate_source_path(copy);
    }
    return Err(e);
}

Prevention

When it happens

Trigger: Calling validate_source_path where the file's st_dev differs from its parent directory's st_dev — typically the file is itself a mountpoint or bind-mounted from another filesystem.

Common situations: A bind mount of a file from another volume over the expected path; the source placed on a tmpfs nested under a disk-backed directory; overlayfs upper/lower differences in containers.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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