dmtrKovalenko/fff · error

fff_search_mixed returned null search result

Error message

fff_search_mixed returned null search result

What it means

The FFI envelope from fff_search_mixed reported success, but its result handle pointer is 0 — meaning the native side returned a null search result even though the call 'succeeded'. The binding treats this as a contract violation and returns an error rather than fabricating an empty result.

Solutions

  1. Ensure the FileFinder instance is alive (not destroyed) when calling mixed search — check handle validity first.
  2. Rebuild/reinstall the native library to rule out version mismatch with the JS bindings.
  3. If reproducible on a healthy instance, report it: a success envelope with a null handle is a native-side bug.

Example fix

// before
const r = ffiSearchMixed(handle, query); // handle may be stale
// after
const alive = ensureAlive(handle);
if (!alive.ok) return alive;
const r = ffiSearchMixed(alive.value, query);
Defensive patterns

Strategy: try-catch

Validate before calling

if (finder === null || !finder.isAlive()) return err('finder destroyed');

Type guard

function isAlive(finder) { return finder != null && finder.handle !== null; }

Try / catch

try { const r = await finder.searchMixed(q); } catch (e) { if (e.message.includes('null search result')) { recreateFinder(); } }

Prevention

When it happens

Trigger: ffiSearchMixed where the native fff_search_mixed produced a success envelope with handlePtr === 0, e.g. native ran with an uninitialized/garbage-collected handle or the native call failed to allocate the result struct.

Common situations: Calling search on a FileFinder whose native instance was already destroyed (double-free / use-after-free scenario); native OOM while allocating the result; a bug in a mismatched native library version.

Related errors


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

Appendix: source

Thrown at packages/fff-bun/src/ffi.ts:908

      modificationFrecencyScore: Number(read.i64(pp, MI_MODFR)),
      totalFrecencyScore: Number(read.i64(pp, MI_TOTAL_FR)),
    },
  };
}

/**
 * Parse an FffMixedSearchResult from a raw FffResult pointer, then free native memory.
 */
function parseMixedSearchResult(resultPtr: Pointer | null): Result<MixedSearchResult> {
  if (resultPtr === null) {
    return err("FFI returned null pointer");
  }

  const envelope = readResultEnvelope(resultPtr);
  if (!("success" in envelope)) return envelope;

  if (envelope.handlePtr === 0) {
    return err("fff_search_mixed returned null search result");
  }

  const hp = asPtr(envelope.handlePtr);
  const count = read.u32(hp, MSR_COUNT);
  const totalMatched = read.u32(hp, MSR_MATCHED);
  const totalFiles = read.u32(hp, MSR_TOTAL_FILES);
  const totalDirs = read.u32(hp, MSR_TOTAL_DIRS);

  // Read location
  const locTag = read.u8(hp, MSR_LOC_TAG);
  let location: Location | undefined;
  if (locTag === 1) {
    location = { type: "line", line: read.i32(hp, MSR_LOC_LINE) };
  } else if (locTag === 2) {
    location = {
      type: "position",
      line: read.i32(hp, MSR_LOC_LINE),
      col: read.i32(hp, MSR_LOC_COL),

View on GitHub (pinned to 7f8537e70f)