dmtrKovalenko/fff · error

Failed to acquire frecency lock

Error message

Failed to acquire frecency lock: {}

What it means

After successfully opening the frecency database, the tracker is installed into the shared global frecency slot via init(). This error means the lock acquisition or initialization of the shared frecency state failed; the underlying cause is included in the message. It is distinct from a failure to open the LMDB file itself.

Solutions

  1. Serialize instance creation (create instances sequentially or under an application-level mutex).
  2. Retry creation once; if the lock is poisoned, the process likely needs restart.
  3. Ensure only one instance initializes the shared frecency db, or use distinct frecency_db_path values per instance if supported.
  4. Check logs for a prior panic that could have poisoned the lock.

Example fix

// before
instances = await Promise.all(paths.map(p => createInstance(p)));
// after
for (const p of paths) instances.push(createInstance(p)); // sequential init
Defensive patterns

Strategy: retry

Try / catch

try {
  createInstanceWithFrecency(opts);
} catch (e) {
  if (/Failed to acquire frecency lock/.test(e.message)) {
    await delay(50);
    return createInstanceWithFrecency(opts); // single retry after contention
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling fff_create_instance* concurrently from multiple threads/processes while another initialization holds the shared frecency lock and fails or contends; poisoned lock from a previous panic during init.

Common situations: Instantiating several instances in parallel at startup in the same process; a previous init panicked, leaving the mutex poisoned; embedded usage with multiple FFI entry points racing.

Related errors


AI-assisted analysis of dmtrKovalenko/fff@7f8537e70f (2026-09-10). Data as JSON: /api/errors/333eb1e397d50ef0. Report an issue: GitHub.

Appendix: source

Thrown at crates/fff-c/src/lib.rs:222

        }
    }

    let frecency_path = unsafe { optional_cstr(opts.frecency_db_path) }.map(|s| s.to_string());
    let history_path = unsafe { optional_cstr(opts.history_db_path) }.map(|s| s.to_string());

    let shared_picker = SharedFilePicker::default();
    let shared_frecency = SharedFrecency::default();
    let query_tracker = SharedQueryTracker::default();

    if let Some(ref frecency_path) = frecency_path {
        if let Some(parent) = PathBuf::from(frecency_path).parent() {
            let _ = std::fs::create_dir_all(parent);
        }

        match FrecencyTracker::open(frecency_path) {
            Ok(tracker) => {
                if let Err(e) = shared_frecency.init(tracker) {
                    return FffResult::err(&format!("Failed to acquire frecency lock: {}", e));
                }
            }
            Err(e) => return FffResult::err(&format!("Failed to init frecency db: {}", e)),
        }
    }

    if let Some(ref history_path) = history_path {
        if let Some(parent) = PathBuf::from(history_path).parent() {
            let _ = std::fs::create_dir_all(parent);
        }

        match QueryTracker::open(history_path) {
            Ok(tracker) => {
                if let Err(e) = query_tracker.init(tracker) {
                    return FffResult::err(&format!("Failed to acquire query tracker lock: {}", e));
                }
            }
            Err(e) => return FffResult::err(&format!("Failed to init query tracker db: {}", e)),

View on GitHub (pinned to 7f8537e70f)