{"record":{"id":"77727573e7445585","repo":"dmtrKovalenko/fff","slug":"fff-search-directories-returned-null-search-result","errorCode":null,"errorMessage":"fff_search_directories returned null search result","messagePattern":"fff_search_directories returned null search result","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/fff-node/src/ffi.ts","lineNumber":1049,"sourceCode":"  const [envelope] = restorePointer({\n    retType: [FFF_RESULT_STRUCT],\n    paramsValue: wrapPointer([rawPtr]),\n  }) as unknown as [FffResultRaw];\n\n  const success = envelope.success !== 0;\n\n  if (!success) {\n    const errorMsg = readCString(envelope.error) || \"Unknown error\";\n    freeResult(rawPtr);\n    return err(errorMsg);\n  }\n\n  const handlePtr = envelope.handle;\n  // Free the FffResult envelope (does NOT free handle)\n  freeResult(rawPtr);\n\n  if (isNullPointer(handlePtr)) {\n    return err(\"fff_search_directories returned null search result\");\n  }\n\n  // Read FffDirSearchResult struct\n  const [sr] = restorePointer({\n    retType: [FFF_DIR_SEARCH_RESULT_STRUCT],\n    paramsValue: wrapPointer([handlePtr]),\n  }) as unknown as [FffDirSearchResultRaw];\n\n  const count = sr.count;\n\n  // Read items and scores via accessor functions\n  const items: DirItem[] = [];\n  const scores: Score[] = [];\n\n  for (let i = 0; i < count; i++) {\n    const rawItem = callAccessor<FffDirItemRaw>(\n      \"fff_dir_search_result_get_item\",\n      handlePtr,","sourceCodeStart":1031,"sourceCodeEnd":1067,"githubUrl":"https://github.com/dmtrKovalenko/fff/blob/7f8537e70f0ea1210f9acbbfc4640141105cdc78/packages/fff-node/src/ffi.ts#L1031-L1067","documentation":"fff_search_directories returned a null handle pointer inside the FffResult envelope, meaning the native library signaled success but produced no FffDirSearchResult. The Node FFI layer treats this as an internal invariant violation because a successful directory search must always yield a result struct. This usually indicates a bug or race in the Rust side rather than a user error.","triggerScenarios":"Calling FileFinder.searchDirectories (via ffiSearchDirectories) when the native fff_search_directories call returns success but a null handle in the envelope — e.g. native code failed to allocate the result struct or a race during shutdown/index teardown.","commonSituations":"Running against a stale or mismatched prebuilt .so/.dll that does not match the TS FFI bindings; searching after the picker's index was torn down; a native bug when the scanned directory set is empty or the handle was already freed.","solutions":["Update the fff-node package and rebuild/download the matching native binary so TS bindings and Rust library versions align.","Verify the FileFinder instance is still alive (not destroyed) before searching and that scanning has completed.","Reproduce with a minimal query; if it persists, file a bug with the native library version and query.","Wrap calls in Result handling and retry the search once — transient races during index rebuild may resolve."],"exampleFix":"// before\nconst res = finder.searchDirectories({ query: 'src' });\nif (!res.ok) throw new Error(res.error);\n// after\nconst res = finder.searchDirectories({ query: 'src' });\nif (!res.ok) {\n  if (res.error.includes('null search result')) {\n    await finder.rescan(); // rebuild native state, then retry\n    return finder.searchDirectories({ query: 'src' });\n  }\n  throw new Error(res.error);\n}","handlingStrategy":"fallback","validationCode":"// no pre-call check possible; verify environment instead\nconst binaryOk = typeof ffiSearchDirectories === 'function' && nativeLibVersion() === expectedVersion;","typeGuard":"function hasSearchHandle(finder: FileFinder): finder is FileFinder & { handle: NativeHandle } {\n  return finder.isAlive();\n}","tryCatchPattern":"const res = finder.searchDirectories({ query });\nif (!res.ok) {\n  if (res.error.includes('null search result')) {\n    await finder.rescan();\n    return finder.searchDirectories({ query }); // one retry\n  }\n  throw new Error(res.error);\n}","preventionTips":["Keep the native binary and fff-node bindings on matching versions.","Recreate the finder rather than reusing it after teardown/rescan cycles.","Log native library version at startup to correlate bugs.","Handle Result errors explicitly instead of assuming success implies a struct."],"tags":["ffi","native","null-pointer"],"backgroundTag":"null-argument","analyzedSha":"7f8537e70f0ea1210f9acbbfc4640141105cdc78","analyzedAt":"2026-09-10T07:26:53.407Z","contentChangedAt":"2026-09-10T07:26:53.407Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}