astrid-runtime/astrid · error

legacy state source is an active mount: {}

Error message

legacy state source is an active mount: {}

What it means

ensure_legacy_tree_boundary rejects a legacy tree root that is itself an active mountpoint (checked via is_active_mountpoint). Deleting a mounted directory would either fail or, worse, let the library descend through the mount; retirement therefore refuses with InvalidData.

Source

Thrown at crates/astrid-core/src/dirs_layout_retirement.rs:248

    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(())
}

#[cfg(target_os = "linux")]
pub(super) fn is_active_mountpoint(path: &Path) -> io::Result<bool> {
    let canonical = std::fs::canonicalize(path)?;
    let mountinfo = std::fs::read_to_string("/proc/self/mountinfo")?;
    Ok(mountinfo.lines().any(|line| {
        let Some(mountpoint) = line.split_whitespace().nth(4) else {
            return false;
        };
        decode_mountinfo_path(mountpoint).is_some_and(|mountpoint| mountpoint == canonical)
    }))
}

View on GitHub (pinned to affd8760f4)

Solutions

  1. Unmount the mountpoint: umount <path> (or stop the systemd mount unit / container holding it), then retry retirement.
  2. Move any data you need off the mounted volume first, since the legacy tree being retired should be empty or disposable.
  3. If a service keeps re-mounting it, disable the mount unit or stop the workload before retiring.

Example fix

// before
mount | grep legacy  -> /dev/sdb1 on /data/legacy
// after
umount /data/legacy
Defensive patterns

Strategy: validation

Validate before calling

fn assert_not_mountpoint(p: &Path) -> io::Result<()> {
    let parent_dev = std::fs::metadata(p.parent().unwrap())?.dev(); // unix
    let dev = std::fs::metadata(p)?.dev();
    if dev != parent_dev {
        return Err(io::Error::new(io::ErrorKind::InvalidData, "active mountpoint"));
    }
    Ok(())
}

Type guard

fn is_mountpoint(p: &Path) -> bool {
    match (std::fs::metadata(p), p.parent().and_then(|q| std::fs::metadata(q).ok())) {
        (Ok(c), Some(par)) => c.dev() != par.dev(),
        _ => false,
    }
}

Try / catch

match retire_legacy_source_tree(&path, dev) {
    Err(e) if e.to_string().contains("active mount") => { /* umount + stop mount units, retry */ }
    other => other?,
}

Prevention

When it happens

Trigger: retire_legacy_source_tree is called while the legacy source path (or, combined with 1205, any entry) is an active mountpoint — e.g. a volume is mounted exactly at the legacy state dir.

Common situations: Container runtime still has a volume mounted at the data path; systemd automount/tmpfs unit active; admin mounted a new disk at the old state location before migration.

Related errors


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