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
- Ensure the fff extension's session_start hook runs (it calls initializeFinderFactories) before any find/grep tool is invoked
- If you changed cwd or ended a session, re-start the session so factories are re-created instead of reusing stale tool handles
- If embedding the extension, call the initialization path explicitly before first tool use
- 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
- Always start the session before invoking find/grep tools
- Create one extension instance per session and discard handles on teardown
- Don't interleave tool calls with session_end events
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
- FFF auxiliary finder pool is not initialized
- File picker not initialized. Call fff_create_instance first.
- Failed to create FFF file picker for
- Failed to init file picker
- watch callback has been closed
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)