astrid-runtime/astrid · error

FUSE service mountpoint is already mounted

Error message

FUSE service mountpoint is already mounted

What it means

validate_mountpoint consults mountinfo (via mountpoint::mountinfo_contains) to confirm the mountpoint is not already an active mount point. Launching FUSE over an existing mount would stack filesystems and break teardown expectations, so the launch is refused.

Solutions

  1. Unmount the existing filesystem at the mountpoint (fusermount -u <mountpoint>) and retry
  2. Stop the previous FUSE service instance before launching a new one with the same mountpoint
  3. Check /proc/self/mountinfo (or `mountpoint <path>`) before launching to confirm the path is free
  4. Use a unique mountpoint per service instance to avoid collisions

Example fix

# before: launching while old mount persists
$ fusermount -u /run/astrid/mounts/demo
# after the mount is gone, relaunch the service
Defensive patterns

Strategy: validation

Validate before calling

let mounted = std::fs::read_to_string("/proc/self/mountinfo")?
    .lines()
    .any(|l| l.split_whitespace().nth(3) == Some(mountpoint.to_str().unwrap()));
if mounted { /* unmount first */ }

Prevention

When it happens

Trigger: Calling validate_launch when the kernel mount table (/proc/self/mountinfo) already lists the mountpoint path as a mounted filesystem — typically a prior FUSE mount that was never unmounted.

Common situations: A previous service instance is still running with the same mountpoint; an unmount failed or was skipped during shutdown; double-starting the service (e.g. systemd unit restarted while the old process lingers).

Related errors


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

Appendix: source

Thrown at crates/astrid-storage-provider-fuse/src/service.rs:266

        || mountpoint.parent().is_none()
    {
        bail!("FUSE service mountpoint is malformed");
    }
    if mountpoint == resource_path
        || mountpoint.starts_with(resource_path)
        || resource_path.starts_with(mountpoint)
    {
        bail!("FUSE service mountpoint overlaps the lease resource");
    }
    platform_fs::validate_private_directory(mountpoint)
        .context("validate private FUSE service mountpoint")?;
    platform_fs::verify_no_redirects(mountpoint)
        .context("reject redirected FUSE service mountpoint")?;
    if std::fs::read_dir(mountpoint)?.next().is_some() {
        bail!("FUSE service mountpoint is not empty");
    }
    if mountpoint::mountinfo_contains(mountpoint)? {
        bail!("FUSE service mountpoint is already mounted");
    }
    Ok(())
}

fn validate_control_path(control_path: &Path, resource_path: &Path) -> Result<()> {
    if !control_path.is_absolute()
        || control_path
            .components()
            .any(|component| matches!(component, std::path::Component::ParentDir))
    {
        bail!("FUSE service control path is malformed");
    }
    if control_path != resource_path.join("process-control.sock") {
        bail!("FUSE service control path is not the kernel endpoint");
    }
    let parent = control_path
        .parent()
        .context("FUSE service control path has no parent")?;

View on GitHub (pinned to affd8760f4)