astrid-runtime/astrid · error

duplicate FUSE provider mountpoint {} in records {} and {}

Error message

duplicate FUSE provider mountpoint {} in records {} and {}

What it means

The registry maps canonical mountpoint paths to mount records. During load_registry, if two record files claim the same mountpoint, inserting the second reveals the duplicate and load_registry aborts, since two mounts on one path is ambiguous and unsafe.

Source

Thrown at crates/astrid-storage-provider-fuse/src/registry.rs:75

        let entry = entry?;
        let path = entry.path();
        if path.extension().is_none_or(|extension| extension != "json") {
            continue;
        }
        let record: MountRecord = serde_json::from_slice(&std::fs::read(&path)?)
            .with_context(|| format!("decode FUSE provider record {}", path.display()))?;
        if path
            .file_stem()
            .is_none_or(|stem| stem.to_string_lossy() != record.mount_id.to_string())
        {
            anyhow::bail!(
                "FUSE provider registry filename does not match its mount identity: {}",
                path.display()
            );
        }
        let key = path_key(&record.mountpoint)?;
        if let Some(existing) = records.insert(key, record.clone()) {
            anyhow::bail!(
                "duplicate FUSE provider mountpoint {} in records {} and {}",
                record.mountpoint.display(),
                existing.mount_id,
                record.mount_id
            );
        }
    }
    Ok(records)
}

/// Atomically persist one private record.
pub(crate) fn write_record(record: &MountRecord) -> Result<()> {
    let directory = registry_directory()?;
    astrid_core::platform_fs::ensure_private_directory(&directory)?;
    let path = record_path(&record.mount_id)?;
    let mut bytes = serde_json::to_vec(record)?;
    bytes.push(b'\n');
    astrid_core::platform_fs::atomic_write_private_file(&path, &bytes)?;

View on GitHub (pinned to affd8760f4)

Solutions

  1. Remove one of the duplicate record files (keep the record with the live mount_id)
  2. Delete stale records for mounts that no longer exist and re-register
  3. Check /proc/mounts to see which mount_id is actually live before choosing
  4. Deduplicate by canonical mountpoint path when restoring registries

Example fix

// before
records: 1111.json {mountpoint:/mnt/fuse}, 2222.json {mountpoint:/mnt/fuse}
// after
rm 2222.json   # keep only the live mount's record
Defensive patterns

Strategy: validation

Validate before calling

fn registry_has_duplicate_mountpoints(paths: &[std::path::PathBuf]) -> std::io::Result<bool> {
    use std::collections::HashSet;
    let mut seen = HashSet::new();
    for p in paths {
        let rec: serde_json::Value = serde_json::from_slice(&std::fs::read(p)?)?;
        if !seen.insert(rec["mountpoint"].as_str().unwrap_or_default().to_string()) {
            return Ok(true);
        }
    }
    Ok(false)
}

Try / catch

match load_registry() {
    Err(e) if e.to_string().contains("duplicate FUSE provider mountpoint") => {
        eprintln!("remove one of the records naming the same mountpoint, then retry");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Two registry record files containing identical mountpoint values (e.g. a file copied or duplicated under a different name, or two sessions registering the same path without cleanup).

Common situations: Manual copy of a record file with a different name; leftover record from a crashed run plus a newly created record for the same path; restoring a backup over an existing registry.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


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