{"record":{"id":"71ed6e87ad50f8f6","repo":"microsoft/garnet","slug":"bftree-scan-with-count-returned-a-null-handle","errorCode":null,"errorMessage":"bftree_scan_with_count returned a null handle.","messagePattern":"bftree_scan_with_count returned a null handle\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"libs/native/bftree-garnet/BfTreeService.cs","lineNumber":307,"sourceCode":"        {\n            return (BfTreeDeleteResult)NativeBfTreeMethods.bftree_delete(treePtr, key.ToPointer(), key.Length);\n        }\n\n        /// <summary>\n        /// Scan with count via native pointer using a zero-allocation callback.\n        /// </summary>\n        /// <returns>Number of records passed to the callback.</returns>\n        public static int ScanWithCountByPtrCallback(nint treePtr, ReadOnlySpan<byte> startKey, int count, ScanReturnField returnField, ScanRecordAction onRecord)\n        {\n            nint handle;\n            fixed (byte* skp = startKey)\n            {\n                handle = NativeBfTreeMethods.bftree_scan_with_count(\n                    treePtr, skp, startKey.Length, count, (byte)returnField);\n            }\n\n            if (handle == nint.Zero)\n                throw new InvalidOperationException(\"bftree_scan_with_count returned a null handle.\");\n\n            try\n            {\n                Span<byte> buffer = stackalloc byte[8192];\n                return DrainScanIteratorWithCallback(handle, buffer, returnField, onRecord);\n            }\n            finally\n            {\n                NativeBfTreeMethods.bftree_scan_drop(handle);\n            }\n        }\n\n        /// <summary>\n        /// Scan with end key via native pointer using a zero-allocation callback.\n        /// </summary>\n        /// <returns>Number of records passed to the callback.</returns>\n        public static int ScanWithEndKeyByPtrCallback(nint treePtr, ReadOnlySpan<byte> startKey, ReadOnlySpan<byte> endKey, ScanReturnField returnField, ScanRecordAction onRecord)\n        {","sourceCodeStart":289,"sourceCodeEnd":325,"githubUrl":"https://github.com/microsoft/garnet/blob/951b0fc6838721f89d102c2bbe1b914e8d39d700/libs/native/bftree-garnet/BfTreeService.cs#L289-L325","documentation":"Thrown by BfTreeService.ScanWithCountByPtrCallback when the native bftree_scan_with_count function returns a null handle (IntPtr.Zero). A null scan handle means the native layer could not begin the scan — typically because the tree pointer is invalid, the tree is in a corrupted state, or an internal native error occurred during scan initialization. The method pins the startKey and passes it to native code.","triggerScenarios":"Calling ScanWithCountByPtrCallback with an invalid or freed treePtr, or when the native tree is in a state that prevents scan initialization. The native bftree_scan_with_count returns 0, which is checked at BfTreeService.cs:306.","commonSituations":"Using a tree pointer from a BfTreeService that has been disposed; passing a raw pointer that was never valid; concurrent disposal of the tree while a scan is being initiated; native memory corruption.","solutions":["Verify the treePtr is valid and the owning BfTreeService has not been disposed.","Ensure scans are not initiated after the tree is closed or during disposal.","Check native error logs or stderr for the specific reason the scan handle was null.","Guard against calling scan methods on freed/invalid pointers by tracking BfTreeService lifecycle."],"exampleFix":"// before: using a disposed tree's pointer\nusing (var svc = new BfTreeService(...))\n{\n    var ptr = svc.TreePointer;\n} // svc disposed here\nBfTreeService.ScanWithCountByPtrCallback(ptr, ...); // invalid ptr\n\n// after: scan within the service lifetime\nusing (var svc = new BfTreeService(...))\n{\n    var ptr = svc.TreePointer;\n    BfTreeService.ScanWithCountByPtrCallback(ptr, ...); // valid\n}","handlingStrategy":"validation","validationCode":"if (treePtr == nint.Zero)\n    throw new InvalidOperationException(\"Cannot scan: tree pointer is null/zero.\");\n// Verify the owning BfTreeService is still alive before calling scan","typeGuard":"static bool IsValidTreePointer(nint treePtr, BfTreeService owner) =>\n    treePtr != nint.Zero && !owner.IsDisposed;","tryCatchPattern":"try\n{\n    BfTreeService.ScanWithCountByPtrCallback(treePtr, startKey, count, returnField, onRecord);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"bftree_scan_with_count returned a null handle\"))\n{\n    logger.LogError(ex, \"BfTree scan failed — tree pointer may be invalid or disposed.\");\n    throw;\n}","preventionTips":["Never use a tree pointer from a disposed BfTreeService.","Track BfTreeService lifecycle and guard scan calls against use-after-dispose.","Avoid concurrent dispose/scan races by synchronizing access.","Log native stderr output for additional diagnostics on scan failures."],"tags":["bftree","native-interop","scan","resource-lifecycle"],"backgroundTag":null,"analyzedSha":"951b0fc6838721f89d102c2bbe1b914e8d39d700","analyzedAt":"2026-08-13T19:01:32.939Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}