astrid-runtime/astrid · error
legacy state source crosses a filesystem boundary: {}
Error message
legacy state source crosses a filesystem boundary: {} What it means
ensure_legacy_tree_boundary compares the st_dev of each directory in the legacy tree against the root device. If any entry lies on a different filesystem (i.e. the tree crosses a mount boundary), it throws InvalidData so deletion never recurses into a separate filesystem and wipes unrelated data.
Source
Thrown at crates/astrid-core/src/dirs_layout_retirement.rs:236
// later operator repair or an idempotent restart.
let root_device = legacy_tree_device(&metadata);
validate_legacy_tree(path, root_device)?;
delete_legacy_tree(path, root_device)?;
let parent = path
.parent()
.ok_or_else(|| io::Error::other("legacy state source has no parent"))?;
sync_directory(parent)
}
fn ensure_legacy_tree_boundary(
path: &Path,
root_device: u64,
metadata: &std::fs::Metadata,
) -> io::Result<()> {
#[cfg(unix)]
{
if legacy_tree_device(metadata) != root_device {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"legacy state source crosses a filesystem boundary: {}",
path.display()
),
));
}
}
#[cfg(not(unix))]
let _ = (root_device, metadata);
if is_active_mountpoint(path)? {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("legacy state source is an active mount: {}", path.display()),
));
}
Ok(())
}View on GitHub (pinned to affd8760f4)
Solutions
- Unmount the nested filesystem (umount <reported path>) so the whole tree lives on one device, then retry.
- Relocate the mounted content into the same filesystem and re-check.
- Use a bind mount at the tree root itself is NOT allowed either — the entire tree must be on one device, so flatten the layout.
Example fix
// before mount | grep legacy -> tmpfs on /data/legacy/tmp // after umount /data/legacy/tmp
Defensive patterns
Strategy: validation
Validate before calling
#[cfg(unix)]
fn same_device(p: &Path, root_dev: u64) -> io::Result<bool> {
use std::os::unix::fs::MetadataExt;
Ok(std::fs::metadata(p)?.dev() == root_dev)
} Type guard
fn crosses_boundary(md: &std::fs::Metadata, root_dev: u64) -> bool {
use std::os::unix::fs::MetadataExt;
md.dev() != root_dev
} Try / catch
match retire_legacy_source_tree(&path, dev) {
Err(e) if e.to_string().contains("filesystem boundary") => eprintln!("umount nested fs first"),
other => other?,
} Prevention
- Never mount volumes inside legacy state subdirectories
- Run `df <path>` / `stat -c %d` checks before retirement
- Keep container volume mounts at or above the state root, not within it
When it happens
Trigger: Any subdirectory inside the legacy tree is a mountpoint or was bind-mounted from another device when validate_legacy_tree or delete_legacy_tree checks boundaries.
Common situations: An admin mounted extra storage at a nested state subdirectory (e.g. tmpfs at legacy/tmp); Docker/Kubernetes volume mounts placed inside the data dir; disk re-partitioning moved part of the tree.
Related errors
- mountpoint is already registered: {}
- legacy state source is an active mount: {}
- legacy source is an active mount: {}
- legacy source crosses a device boundary: {}
- directory symlink {} not allowed in capsule source tree (ref
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/5f2606e8bdd7f74f.
Report an issue: GitHub.