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
- Call GetNext(out RecordInfo recordInfo) and access the record via reference APIs (GetKey/GetValue or ref Get* methods) before moving to the next record.
- If you need durable copies, materialize key/value with ConvertToRecord or copy to your own structs immediately after GetNext.
- Refactor shared scan helpers to call the RecordInfo overload, or special-case the varlen blittable iterator.
- 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
- Never call the 3-out GetNext overload on varlen blittable iterators
- Copy/convert the record (ConvertToRecord) before advancing the iterator if you need it later
- Keep object-iterator and by-ref-iterator code paths separate
- Let the compiler see the concrete iterator type instead of routing through shared overloads
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
- Cannot use BlittableParameterSerializer with non-blittable…
- AsyncReadRecordObjectsToMemory invalid for…
- BlittableAllocator memory pages are sector aligned - use…
- Page read from storage failed, skipping page. Inner…
- AsyncReadRecordObjectsToMemory invalid for…
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)