{"record":{"id":"6751887bda0d2959","repo":"dmtrKovalenko/fff","slug":"scan-progress-returned-null-675188","errorCode":null,"errorMessage":"scan progress returned null","messagePattern":"scan progress returned null","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/fff-node/src/ffi.ts","lineNumber":1534,"sourceCode":"}\n\n/**\n * Get scan progress.\n */\nexport function ffiGetScanProgress(handle: NativeHandle): Result<{\n  scannedFilesCount: number;\n  isScanning: boolean;\n  isWatcherReady: boolean;\n  isWarmupComplete: boolean;\n}> {\n  loadLibrary();\n  const res = readResultEnvelope(\"fff_get_scan_progress\", [DataType.External], [handle]);\n  if (\"ok\" in res) return res;\n\n  const handlePtr = res.struct.handle;\n  freeResult(res.rawPtr);\n\n  if (isNullPointer(handlePtr)) return err(\"scan progress returned null\");\n\n  const [sp] = restorePointer({\n    retType: [FFF_SCAN_PROGRESS_STRUCT],\n    paramsValue: wrapPointer([handlePtr]),\n  }) as unknown as [FffScanProgressRaw];\n\n  const result = {\n    scannedFilesCount: Number(sp.scanned_files_count),\n    isScanning: sp.is_scanning !== 0,\n    isWatcherReady: sp.is_watcher_ready !== 0,\n    isWarmupComplete: sp.is_warmup_complete !== 0,\n  };\n\n  // Free native scan progress\n  load({\n    library: LIBRARY_KEY,\n    funcName: \"fff_free_scan_progress\",\n    retType: DataType.Void,","sourceCodeStart":1516,"sourceCodeEnd":1552,"githubUrl":"https://github.com/dmtrKovalenko/fff/blob/7f8537e70f0ea1210f9acbbfc4640141105cdc78/packages/fff-node/src/ffi.ts#L1516-L1552","documentation":"fff_get_scan_progress returned a null handle for the scan-progress struct even though the envelope reported success. The FFI layer cannot read FffScanProgress without a valid pointer, so it errors with \"scan progress returned null\". This means the native side has no progress object to hand out, typically because scanning has not started or the state was reset.","triggerScenarios":"Calling FileFinder.getScanProgress when no scan has been initiated for the instance, after a rescan reset cleared progress state, or when the native binary fails to allocate the FffScanProgress struct.","commonSituations":"Polling progress right after construction before the background scan spawned; polling after the picker/index was reinitialized; version-mismatched native binary lacking progress support.","solutions":["Only poll scan progress after triggering a scan/rescan and confirming the instance is alive.","Treat this error as \"no progress available yet\" and retry after a short delay.","Rebuild/upgrade the native binary if it predates scan-progress support.","If it persists on an active scan, report a bug with the native library version."],"exampleFix":"// before\nconst p = finder.getScanProgress();\nif (!p.ok) throw new Error(p.error);\n// after\nconst p = finder.getScanProgress();\nif (!p.ok) {\n  if (p.error.includes('null')) return { scanned: 0, total: 0, done: false }; // no scan yet\n  throw new Error(p.error);\n}","handlingStrategy":"fallback","validationCode":"// only poll after a scan was requested and the finder is alive\nif (!finder.isAlive() || !scanRequested) skipProgressPoll();","typeGuard":"function hasProgress(p: Result<ScanProgress>): p is { ok: true; value: ScanProgress } { return p.ok; }","tryCatchPattern":"const p = finder.getScanProgress();\nconst progress = p.ok ? p.value : { scanned: 0, total: 0, done: false }; // graceful default","preventionTips":["Start polling only after triggering a scan.","Treat missing progress as 'not started' rather than a hard failure.","Match native binary and binding versions.","Debounce progress polling to avoid racing state resets."],"tags":["ffi","native","scan-progress"],"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"}