microsoft/garnet · error · InvalidOperationException

bftree_scan_with_end_key returned a null handle.

Error message

bftree_scan_with_end_key returned a null handle.

What it means

Thrown by BfTreeService.ScanWithEndKeyByPtrCallback when the native bftree_scan_with_end_key function returns a null handle. Similar to the count-based scan, a null handle means the native layer could not start the range scan. This variant takes both a startKey and endKey to define the scan range; invalid or inverted key ranges may also contribute to failure.

Source

Thrown at libs/native/bftree-garnet/BfTreeService.cs:334

                NativeBfTreeMethods.bftree_scan_drop(handle);
            }
        }

        /// <summary>
        /// Scan with end key via native pointer using a zero-allocation callback.
        /// </summary>
        /// <returns>Number of records passed to the callback.</returns>
        public static int ScanWithEndKeyByPtrCallback(nint treePtr, ReadOnlySpan<byte> startKey, ReadOnlySpan<byte> endKey, ScanReturnField returnField, ScanRecordAction onRecord)
        {
            nint handle;
            fixed (byte* skp = startKey, ekp = endKey)
            {
                handle = NativeBfTreeMethods.bftree_scan_with_end_key(
                    treePtr, skp, startKey.Length, ekp, endKey.Length, (byte)returnField);
            }

            if (handle == nint.Zero)
                throw new InvalidOperationException("bftree_scan_with_end_key returned a null handle.");

            try
            {
                Span<byte> buffer = stackalloc byte[8192];
                return DrainScanIteratorWithCallback(handle, buffer, returnField, onRecord);
            }
            finally
            {
                NativeBfTreeMethods.bftree_scan_drop(handle);
            }
        }

        // ---------------------------------------------------------------
        // Point operations — span-based (safe wrappers: fixed → PinnedSpanByte → native)
        // ---------------------------------------------------------------

        /// <summary>
        /// Insert a key-value pair into the BfTree.

View on GitHub (pinned to 951b0fc683)

Solutions

  1. Verify the treePtr is from a live (non-disposed) BfTreeService.
  2. Ensure the startKey and endKey define a valid, non-inverted range for the tree's key ordering.
  3. Check native logs for the specific scan initialization failure.
  4. Avoid concurrent scan/dispose races by synchronizing access to the tree.

Example fix

// before: inverted key range
BfTreeService.ScanWithEndKeyByPtrCallback(
    treePtr,
    startKey: Encoding.UTF8.GetBytes("zzz"),  // after endKey
    endKey: Encoding.UTF8.GetBytes("aaa"),     // before startKey
    returnField, onRecord);

// after: correct order
BfTreeService.ScanWithEndKeyByPtrCallback(
    treePtr,
    startKey: Encoding.UTF8.GetBytes("aaa"),
    endKey: Encoding.UTF8.GetBytes("zzz"),
    returnField, onRecord);
Defensive patterns

Strategy: validation

Validate before calling

if (treePtr == nint.Zero)
    throw new InvalidOperationException("Cannot scan: tree pointer is null/zero.");
// Ensure startKey <= endKey lexicographically
if (startKey.ToArray().SequenceEqual(endKey.ToArray()) == false)
{
    var cmp = new ReadOnlySpan<byte>(startKey.ToArray()).SequenceCompareTo(endKey);
    if (cmp > 0)
        throw new ArgumentException("startKey must be lexicographically <= endKey.");
}

Type guard

static bool IsValidScanRange(ReadOnlySpan<byte> startKey, ReadOnlySpan<byte> endKey) =>
    startKey.SequenceCompareTo(endKey) <= 0;

Try / catch

try
{
    BfTreeService.ScanWithEndKeyByPtrCallback(treePtr, startKey, endKey, returnField, onRecord);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("bftree_scan_with_end_key returned a null handle"))
{
    logger.LogError(ex, "BfTree range scan failed — check tree pointer validity and key ordering.");
    throw;
}

Prevention

When it happens

Trigger: Calling ScanWithEndKeyByPtrCallback with an invalid/freed treePtr, or with startKey/endKey values the native layer rejects. The check is at BfTreeService.cs:333. Both keys are pinned and passed to native code.

Common situations: Using a tree pointer from a disposed BfTreeService; passing an endKey that sorts before the startKey (inverted range) causing native rejection; corrupted tree state; native memory issues.

Related errors


AI-assisted analysis of microsoft/garnet@951b0fc683 (2026-08-13). Data as JSON: /api/errors/eb2721d4a10cdd3d. Report an issue: GitHub.