dmtrKovalenko/fff · error
FileFinder instance has been destroyed.
Error message
FileFinder instance has been destroyed.
What it means
FileFinder wraps a native handle that becomes null after destroy(). ensureAlive is the guard every method runs through; if the instance was already destroyed (or never successfully created), any further operation returns this error instead of dereferencing a null native handle.
Solutions
- Check the returned Result and stop using the instance after this error; create a new FileFinder if needed.
- Set this.handle = null-sentinel ownership in one place: after destroy(), remove all references other components hold.
- Cancel pending async work (intervals, queued searches) in your destroy/teardown path before or right after calling destroy().
Example fix
// before
async function refresh(finder) { return finder.search("foo"); } // finder may be destroyed
// after
async function refresh(finder) {
const alive = finder.ensureAlive();
if (!alive.ok) return; // instance destroyed, skip
return finder.search("foo");
} Defensive patterns
Strategy: try-catch
Validate before calling
if (finder === null) throw new Error('FileFinder instance has been destroyed.'); Type guard
function isUsableFinder(f) { return f instanceof FileFinder && f.handle !== null; } Try / catch
try { const r = finder.search(q); } catch (e) { if (e.message.includes('has been destroyed')) { finder = await FileFinder.create(opts); return finder.search(q); } } Prevention
- Null out every reference to the finder after destroy().
- Cancel async work (intervals, queued requests) during teardown.
- Wrap native calls in a helper that checks aliveness before delegating.
When it happens
Trigger: Calling any FileFinder method (search, grep, getScanProgress, watch, destroy, etc.) after destroy() was called, or after a failed async init that never assigned this.handle.
Common situations: Event handlers or timers firing after teardown; calling search from a stale reference cached elsewhere; awaiting an operation while another code path destroyed the finder; double-destroy in cleanup logic.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- File picker not initialized. Call fff_create_instance first.
- FFF picker factory is not initialized
- FFF auxiliary finder pool is not initialized
- Instance handle is null. Create one with…
- opts is null
AI-assisted analysis of dmtrKovalenko/fff@7f8537e70f (2026-09-10).
Data as JSON: /api/errors/4db2ce095ba8b17a.
Report an issue: GitHub.
Appendix: source
Thrown at packages/fff-bun/src/finder.ts:186
// benign id-map miss before the trampoline is closed.
this.watchJsCallback?.close();
this.watchJsCallback = null;
}
}
/**
* Check if this instance has been destroyed.
*/
get isDestroyed(): boolean {
return this.handle === null;
}
/**
* Guard that returns an error if the instance has been destroyed.
*/
private ensureAlive(): Result<NativeHandle> {
if (this.handle === null) {
return err("FileFinder instance has been destroyed.");
}
return { ok: true, value: this.handle };
}
/**
* Search for files matching the query.
*
* The query supports fuzzy matching and special syntax:
* - `foo bar` - Match files containing "foo" and "bar"
* - `src/` - Match files in src directory
* - `file.ts:42` - Match file.ts with line 42
* - `file.ts:42:10` - Match file.ts with line 42, column 10
*
* @param query - Search query string
* @param options - Search options
* @returns Search results with matched files and scores
*
* @exampleView on GitHub (pinned to 7f8537e70f)