astrid-runtime/astrid · error

lock FUSE provider lifecycle registry

Error message

lock FUSE provider lifecycle registry: {error}

What it means

The FUSE provider serializes lifecycle operations with an exclusive flock on <registry-dir>/.lock. lock_registry opens/creates that file and takes Flock::lock exclusively; if flock fails, the underlying io::Error is wrapped as this message.

Solutions

  1. Check for another astrid FUSE process holding the lock (lsof/fuser on the .lock file) and wait or kill it
  2. Ensure the registry directory is on a local filesystem that supports flock
  3. Fix permissions so the current user can create/write <registry-dir>/.lock (mode 0o600)
  4. Remove a stale .lock file left by a dead process if no holder exists

Example fix

// before: bare failure
Flock::lock(file, FlockArg::LockExclusive)
    .map_err(|(_, error)| anyhow::anyhow!("lock FUSE provider lifecycle registry: {error}"))
// after: retry with timeout before giving up
Flock::lock(file, FlockArg::LockExclusive)
    .map_err(|(_, error)| anyhow::anyhow!("lock FUSE provider lifecycle registry: {error}"))
    .with_context(|| format!("registry dir: {}", directory.display()))
Defensive patterns

Strategy: try-catch

Validate before calling

// check no live holder before locking
let holder = std::process::Command::new("fuser")
    .arg(directory.join(".lock"))
    .output(); // non-empty output means a process holds it

Try / catch

match lock_registry() {
    Err(e) if e.to_string().contains("lock FUSE provider lifecycle registry") => {
        // wait/backoff, or remove stale .lock if no holder
    }
    r => r,
}

Prevention

When it happens

Trigger: Two mount/unmount operations racing and one process dying while holding the lock; the lock file living on a filesystem that does not support flock (some network FS); permission problems creating/opening .lock in the registry directory.

Common situations: Concurrent astrid mount/unmount commands from multiple shells or systemd units; a container with the registry dir on an NFS/overlay volume lacking flock support; read-only or wrong-permission XDG/state directory.

Understand the failure class

Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.

Related errors


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

Appendix: source

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

    pub auto_created_mountpoint: bool,
    /// Private detached-service control socket.
    pub control_path: PathBuf,
}

/// Acquire the process-wide lifecycle lock used to serialize mount admission.
pub(crate) fn lock_registry() -> Result<Flock<File>> {
    let directory = registry_directory()?;
    astrid_core::platform_fs::ensure_private_directory(&directory)?;
    let file = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .truncate(false)
        .mode(0o600)
        .open(directory.join(".lock"))
        .context("open FUSE provider lifecycle lock")?;
    Flock::lock(file, FlockArg::LockExclusive)
        .map_err(|(_, error)| anyhow::anyhow!("lock FUSE provider lifecycle registry: {error}"))
}

/// Load all records in mount-id order.
pub(crate) fn load_registry() -> Result<BTreeMap<String, MountRecord>> {
    let directory = registry_directory()?;
    let mut records = BTreeMap::new();
    let entries = std::fs::read_dir(&directory);
    let entries = match entries {
        Ok(entries) => entries,
        Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Ok(records),
        Err(error) => return Err(error).context("read FUSE provider registry"),
    };
    for entry in entries {
        let entry = entry?;
        let path = entry.path();
        if path.extension().is_none_or(|extension| extension != "json") {
            continue;
        }

View on GitHub (pinned to affd8760f4)