microsoft/garnet · error · ArgumentOutOfRangeException

start {nameof(start)} + len {len} exceeds length {length}

Error message

start {nameof(start)} + len {len} exceeds length {length}

What it means

AsReadOnlySpan(int start, int len) returns len bytes of the valid region beginning at start. It uses an overflow-safe check — (uint)start + (uint)len <= (uint)length — and throws ArgumentOutOfRangeException when the requested window runs past Length. This is the two-argument bounds guard for native-pointer slice creation.

Source

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

        /// <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));
        }
        /// <summary>ReadOnlySpan of data between offsets</summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public readonly Span<byte> AsSpan(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}");
        }

View on GitHub (pinned to 951b0fc683)

Solutions

  1. Clamp/validate that (ulong)(uint)start + (ulong)(uint)len <= (ulong)(uint)oba.Length before calling.
  2. Verify the source record's ActualSize/filler length matches the len you intend to read.
  3. Use the record's RecordFieldInfo to obtain authoritative field lengths instead of recomputing.
  4. Treat any negative start/len as a programmer error and reject before the call.

Example fix

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

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

Strategy: validation

Validate before calling

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

Prevention

When it happens

Trigger: Calling AsReadOnlySpan(start, len) where start+len exceeds Length, including the integer-overflow case where a negative start or len would otherwise wrap past the end. Triggered by reading more value bytes than the record stores, or miscomputing len from header fields.

Common situations: Reading a value field of declared length N from an overflow region shorter than N (corrupt/truncated record); copying a fixed-size header that the shrunken record no longer fully contains; arithmetic that adds StartOffset twice.

Related errors


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