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
- Unmount the separate filesystem mounted at the reported principal path (umount) and re-run the migration.
- Move the principal's data onto the same filesystem as the home root and remove the mount.
- Keep the extra mount, but relocate it outside the principal home root tree.
- 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
- Keep all principal directories on the same filesystem as the home root.
- Check with `df <path>` / st_dev comparison before scheduling the migration.
- Mount extra volumes outside the principal home tree.
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
- legacy source is an active mount: {}
- legacy source crosses a mount or device boundary: {}
- legacy audit tree crosses a filesystem or mount boundary: {}
- legacy source crosses a device boundary: {}
- legacy capsule directory is not a regular directory: {}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/c049d9addfb5a0c5.
Report an issue: GitHub.