dmtrKovalenko/fff · error · Error

FFF picker factory is not initialized

Error message

FFF picker factory is not initialized

What it means

This error means the FilePickerFactory (`pickers`) is null when `ensureFinder` tries to create the main picker. The factory is created once by `initializeFinderFactories()` and nulled by `destroyFinder()` (e.g. on session end or cwd change teardown). Throwing is a fail-fast guard against using the picker subsystem after teardown or before init instead of silently creating pickers with no database backing.

Solutions

  1. Ensure the fff extension's session_start hook runs (it calls initializeFinderFactories) before any find/grep tool is invoked
  2. If you changed cwd or ended a session, re-start the session so factories are re-created instead of reusing stale tool handles
  3. If embedding the extension, call the initialization path explicitly before first tool use
  4. Do not call tool handlers after session shutdown; create a fresh extension instance per session

Example fix

// before
grepTool.execute(id, params) // fired after session teardown

// after
if (!sessionActive) await startSession(); // re-initializes pickers
await grepTool.execute(id, params)
Defensive patterns

Strategy: try-catch

Validate before calling

if (!fff.isInitialized?.()) await startSession();

Type guard

function hasFactory(e: { isReady?: () => boolean }): boolean { return typeof e.isReady === 'function' && e.isReady(); }

Try / catch

try { await ensureFinder(cwd); } catch (e) { if (String(e).includes('not initialized')) { await startSession(); await ensureFinder(cwd); } else throw e; }

Prevention

When it happens

Trigger: Calling `ensureFinder` (directly or via the find/grep/multiGrep tools) after `destroyFinder()` has run; or calling tools before the extension's session_start event ran `initializeFinderFactories()`. A stale/corrupted LMDB lock does NOT cause this — the factory falls back to a db-less picker for that.

Common situations: Invoking a tool handler from a second session after the first one shut down; racing the extension lifecycle so a tool fires during teardown; embedding the extension programmatically and forgetting to emit session_start before calling tools.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at packages/pi-fff/src/index.ts:479

  }

  // in case cwd changes we need to figure this out
  function ensureFinder(cwd: string): Promise<FileFinderApi> {
    if (mainFinder && !mainFinder.isDestroyed && finderCwd === cwd)
      return Promise.resolve(mainFinder);

    if (finderPromise) return finderPromise;

    finderPromise = (async () => {
      if (mainFinder && !mainFinder.isDestroyed) {
        mainFinder.destroy();
        mainFinder = null;
        finderCwd = null;
      }

      // if the dbs can't be opened the factory falls back to a db-less picker,
      // e.g. when some other process corrupts the lock
      if (!pickers) throw new Error("FFF picker factory is not initialized");
      mainFinder = await pickers.create({
        basePath: cwd,
        enableHomeDirScanning,
        enableFsRootScanning,
        followSymlinks,
      });
      finderCwd = cwd;
      return mainFinder;
    })().finally(() => {
      finderPromise = null;
    });

    return finderPromise;
  }

  function stopHomeScanStatus(): void {
    if (homeScanTimer) {
      clearInterval(homeScanTimer);

View on GitHub (pinned to 7f8537e70f)