microsoft/FASTER · error · NotSupportedException

Use GetNext(out RecordInfo) to retrieve references to…

Error message

Use GetNext(out RecordInfo) to retrieve references to key/value

What it means

VarLenBlittableScanIterator's GetNext overload that returns key and value by value is intentionally not supported: the blittable iterator works by reference into the log's memory pages, which can be invalidated by subsequent reads. Callers must use GetNext(out RecordInfo) and then read the key/value references (e.g. via iterator.GetKey/GetValue or ConvertToRecord) before advancing. The method throws NotSupportedException as a compile-time-visible API deterrent.

Solutions

  1. Call GetNext(out RecordInfo recordInfo) and access the record via reference APIs (GetKey/GetValue or ref Get* methods) before moving to the next record.
  2. If you need durable copies, materialize key/value with ConvertToRecord or copy to your own structs immediately after GetNext.
  3. Refactor shared scan helpers to call the RecordInfo overload, or special-case the varlen blittable iterator.
  4. Compile-time: avoid the 3-out overload in new code; it exists only to fail fast.

Example fix

// before
while (iter.GetNext(out RecordInfo info, out MyKey key, out MyValue value)) { Process(key, value); }
// after
while (iter.GetNext(out RecordInfo info)) {
    ref var key = ref iter.GetKey();
    ref var value = ref iter.GetValue();
    Process(key, value);
}
Defensive patterns

Strategy: type-guard

Validate before calling

// use the supported overload only
if (iter is VarLenBlittableScanIterator<K, V>)
    iter.GetNext(out RecordInfo info); // then ref GetKey()/GetValue()

Type guard

static bool IsByRefScanIterator<K, V>(ScanIteratorBase<K, V> iter)
    => iter is VarLenBlittableScanIterator<K, V>;

Prevention

When it happens

Trigger: Calling the public GetNext(out RecordInfo, out Key, out Value) overload on a VarLenBlittableScanIterator instance — often via code written for the IObjectAllocator scan iterator whose GetNext returns copies of key/value objects.

Common situations: Reusing generic scan helper code that was written for ObjectAllocator's by-value iterator; LINQ or interface-driven code calling the 3-out overload through a shared abstraction; migrating from the classic BlittableAllocator ScanIterator to VarLenBlittableScanIterator.

Understand the failure class

Background: "is deprecated and will be removed" — deprecation warnings for old API names, keywords, and options, and how to migrate before the removal release — this error's family across 29 libraries.

Related errors


AI-assisted analysis of microsoft/FASTER@321d872eab (2026-09-15). Data as JSON: /api/errors/56ee084ce1a65aa8. Report an issue: GitHub.

Appendix: source

Thrown at cs/src/core/Allocator/VarLenBlittableScanIterator.cs:233

        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        long GetPhysicalAddress(long currentAddress, long headAddress, long currentPage, long offset)
        {
            long physicalAddress;
            if (currentAddress >= headAddress || forceInMemory)
                physicalAddress = hlog.GetPhysicalAddress(currentAddress);
            else
                physicalAddress = frame.GetPhysicalAddress(currentPage % frameSize, offset);
            return physicalAddress;
        }

        /// <summary>
        /// Get next record in iterator
        /// </summary>
        /// <returns></returns>
        public bool GetNext(out RecordInfo recordInfo, out Key key, out Value value)
            => throw new NotSupportedException("Use GetNext(out RecordInfo) to retrieve references to key/value");

        /// <summary>
        /// Dispose iterator
        /// </summary>
        public override void Dispose()
        {
            base.Dispose();
            memory?.Return();
            memory = null;
            frame?.Dispose();
        }

        internal override void AsyncReadPagesFromDeviceToFrame<TContext>(long readPageStart, int numPages, long untilAddress, TContext context, out CountdownEvent completed, long devicePageOffset = 0, IDevice device = null, IDevice objectLogDevice = null, CancellationTokenSource cts = null)
            => hlog.AsyncReadPagesFromDeviceToFrame(readPageStart, numPages, untilAddress, AsyncReadPagesCallback, context, frame, out completed, devicePageOffset, device, objectLogDevice);

        private unsafe void AsyncReadPagesCallback(uint errorCode, uint numBytes, object context)
        {
            var result = (PageAsyncReadResult<Empty>)context;

View on GitHub (pinned to 321d872eab)