astrid-runtime/astrid · error

cannot unmount a relative mountpoint

Error message

cannot unmount a relative mountpoint

What it means

lazy_unmount only performs a lazy detach (umount2 with MNT_DETACH) on absolute paths; a relative path could resolve to a different location depending on cwd, so it is rejected up front. This keeps the unmount target unambiguous.

Solutions

  1. Canonicalize the path before unmounting (std::fs::canonicalize or store the canonical path from prepare_mountpoint)
  2. Ensure the path is absolute (starts with /) before calling lazy_unmount
  3. Persist the canonical mountpoint returned by the mount flow, not the user input

Example fix

// before
lazy_unmount(Path::new("./mount"))?
// after
let canonical = std::fs::canonicalize("./mount")?;
lazy_unmount(&canonical)?
Defensive patterns

Strategy: validation

Validate before calling

fn ensure_absolute(path: &std::path::Path) -> Option<&std::path::Path> {
    path.is_absolute().then_some(path)
}

Type guard

fn is_absolute_path(path: &std::path::Path) -> bool {
    path.is_absolute()
}

Try / catch

match lazy_unmount(path) {
    Err(e) if e.to_string().contains("relative mountpoint") => {
        let canonical = std::fs::canonicalize(path)?;
        lazy_unmount(&canonical)?
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling lazy_unmount with a relative Path (e.g. "my-mount" or "./mount") instead of an absolute path; passing a mountpoint string that was never canonicalized.

Common situations: Storing the user-supplied mountpoint string in config instead of the canonical path returned by prepare_mountpoint; reconstructing the path relative to a working directory.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at crates/astrid-storage-provider-fuse/src/mountpoint.rs:76

        .canonicalize()
        .with_context(|| format!("canonicalize mountpoint {}", requested.display()))?;
    if mountinfo_contains(&canonical)? {
        bail!("mountpoint is already mounted: {}", canonical.display());
    }
    Ok((canonical, !existed))
}

/// Return current owner identity for synthetic inode metadata.
pub(crate) fn owner_ids() -> (u32, u32) {
    (getuid().into(), getgid().into())
}

/// Remove a dead FUSE mount if one remains at an exact canonical path.
pub(crate) fn lazy_unmount(mountpoint: &Path) -> Result<()> {
    use nix::mount::MntFlags;

    if !mountpoint.is_absolute() {
        bail!("cannot unmount a relative mountpoint");
    }
    match nix::mount::umount2(mountpoint, MntFlags::MNT_DETACH) {
        Ok(()) | Err(nix::errno::Errno::EINVAL) => Ok(()),
        Err(error) => Err(anyhow::anyhow!(
            "lazy unmount {}: {error}",
            mountpoint.display()
        )),
    }
}

/// Whether `/proc/self/mountinfo` has a mount at this exact path.
pub(crate) fn mountinfo_contains(mountpoint: &Path) -> Result<bool> {
    let expected = mountpoint
        .to_str()
        .context("mountpoint must be canonical Unicode text")?
        .as_bytes();
    let mounts = std::fs::read("/proc/self/mountinfo").context("read Linux mount table")?;
    Ok(mounts

View on GitHub (pinned to affd8760f4)