microsoft/garnet · error · ArgumentOutOfRangeException

start

Error message

start

What it means

OverflowByteArray wraps a backing byte[] with StartOffset and EndOffset, exposing only the region between them as the logical 'value'. AsReadOnlySpan(int start) returns the remainder of that valid region beginning at start; it throws ArgumentOutOfRangeException(nameof(start)) when start is strictly greater than Length (the valid region size). This guards native-pointer slice creation against out-of-range starts.

Source

Thrown at libs/storage/Tsavorite/cs/src/core/Allocator/OverflowByteArray.cs:51

        /// <summary>The total heap size of the array (includes space for offset values and .net array overhead)</summary>
        public readonly int HeapMemorySize => Array is null ? 0 : Array.Length + MemoryUtils.ByteArrayOverhead;

        readonly int EndOffset => Unsafe.As<byte, OverflowHeader>(ref Array[0]).endOffset;

        internal readonly int Length => Array.Length - StartOffset - EndOffset;

        /// <inheritdoc/>
        public override string ToString() => $"Len {Length}, IsEmpty {IsEmpty}, sOffset {StartOffset}, eOffset {EndOffset}, HeapMemSize {HeapMemorySize}, TotSize {TotalSize}";

        /// <summary>ReadOnlySpan of data between offsets</summary>
        internal readonly ReadOnlySpan<byte> ReadOnlySpan => Array.AsSpan(StartOffset, Length);
        /// <summary>ReadOnlySpan of data between offsets</summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public readonly ReadOnlySpan<byte> AsReadOnlySpan(int start)
        {
            var length = Length;
            return start <= length ? Array.AsSpan(StartOffset + start, length - start) : throw new ArgumentOutOfRangeException(nameof(start));
        }
        /// <summary>ReadOnlySpan of data between offsets</summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public readonly ReadOnlySpan<byte> AsReadOnlySpan(int start, int len)
        {
            var length = Length;
            return ((ulong)(uint)start + (uint)len <= (uint)length) ? Array.AsSpan(StartOffset + start, len) : throw new ArgumentOutOfRangeException($"start {nameof(start)} + len {len} exceeds length {length}");
        }

        /// <summary>Span of data between offsets</summary>
        internal readonly Span<byte> Span => Array.AsSpan(StartOffset, Length);
        /// <summary>Span of data between offsets</summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public readonly Span<byte> AsSpan(int start)
        {
            var length = Length;
            return start <= length ? Array.AsSpan(StartOffset + start, length - start) : throw new ArgumentOutOfRangeException(nameof(start));
        }

View on GitHub (pinned to 951b0fc683)

Solutions

  1. Validate start against oba.Length before slicing.
  2. Derive offsets from the record's own header fields (ActualSize, StartOffset) rather than external math.
  3. Confirm the record was not truncated (check ActualSize and filler length) before slicing its overflow bytes.
  4. Add a debug assertion logging start/Length so bad offsets surface early.

Example fix

// before
var span = overflow.AsReadOnlySpan(offset);

// after
if ((uint)offset > (uint)overflow.Length)
    throw new InvalidOperationException($"bad offset {offset} > {overflow.Length}");
var span = overflow.AsReadOnlySpan(offset);
Defensive patterns

Strategy: validation

Validate before calling

if ((uint)start > (uint)overflow.Length)
    throw new InvalidOperationException($"start {start} > Length {overflow.Length}");
var span = overflow.AsReadOnlySpan(start);

Prevention

When it happens

Trigger: Calling AsReadOnlySpan(start) with start > Length — typically from miscomputed offsets when parsing a record's value region, reading a partially-overwritten or truncated overflow record, or off-by-one arithmetic against the record header.

Common situations: Forgetting StartOffset / OverflowHeader.Size when computing an offset; slicing past a value that was shrunk (filler truncation); corrupted or short reads from device; generic span-slicing code that ignores the array's logical bounds.

Related errors


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