dmtrKovalenko/fff · critical

FFI returned null pointer

Error message

FFI returned null pointer

What it means

parseMixedSearchResult received NULL from the native fff_search_mixed symbol. readResultEnvelope could not even read an FffResult envelope, so the binding reports a null-pointer FFI failure. This indicates the native library returned no allocation at all — typically an ABI mismatch, unloaded/incompatible library, or symbol contract violation.

Solutions

  1. Rebuild/reinstall the native library so it matches the JS bindings (rerun the package's install/build step).
  2. Verify the loaded library version matches the ffi.ts bindings (same package version, no cached stale artifact).
  3. Check for a native crash around the call — run with debug logging or test the same call from a minimal C harness.

Example fix

// before
// stale prebuilt binary after upgrading fff-bun
npm install
// after
// force rebuild of the native artifact
npm rebuild fff-bun
Defensive patterns

Strategy: try-catch

Validate before calling

if (!libraryLoaded || !library.symbols.fff_search_mixed) throw new Error('native library not loaded');

Type guard

function isResultPtr(p) { return p !== null && p !== undefined; }

Try / catch

try { const r = ffiSearchMixed(handle, q); } catch (e) { if (e.message === 'FFI returned null pointer') { await rebuildNativeLib(); retry(); } }

Prevention

When it happens

Trigger: Calling ffiSearchMixed when the loaded .so/.dylib/.dll version does not match the TypeScript bindings (struct/ABI drift), or the native code crashed/returned NULL due to an unexpected internal error.

Common situations: Stale prebuilt binary after upgrading the package (build artifacts not rebuilt); mixing bindings from one version with a native library from another; corrupted download in a postinstall step.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


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

Appendix: source

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

    item: {
      relativePath: readCString(read.ptr(pp, MI_RELPATH)) ?? "",
      fileName: readCString(read.ptr(pp, MI_DISPLAY)) ?? "",
      gitStatus: readCString(read.ptr(pp, MI_GIT)) ?? "",
      size: Number(read.u64(pp, MI_SIZE)),
      modified: Number(read.u64(pp, MI_MODIFIED)),
      accessFrecencyScore: Number(read.i64(pp, MI_ACCESS)),
      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;

View on GitHub (pinned to 7f8537e70f)