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
- Move or copy the file onto the same filesystem as its parent directory, then validate the copy.
- Remove the cross-device bind mount so the path is a normal file on the parent filesystem.
- 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
- Check st_dev equality between file and parent before validation.
- Keep source files on the same filesystem as their directory.
- Avoid nested tmpfs/bind mounts at source locations.
- Use df <path> to confirm which filesystem hosts the file.
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
- mountpoint is already registered: {}
- legacy state source crosses a filesystem boundary: {}
- legacy state source is an active mount: {}
- legacy source is an active mount: {}
- legacy principal-home entry crosses a filesystem boundary: {
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/2c0f9b3c514ea8ff.
Report an issue: GitHub.