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

  1. Check the returned Result and stop using the instance after this error; create a new FileFinder if needed.
  2. Set this.handle = null-sentinel ownership in one place: after destroy(), remove all references other components hold.
  3. 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

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


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
   *
   * @example

View on GitHub (pinned to 7f8537e70f)