microsoft/garnet · error · TsavoriteException

Max inline key size is {1 << LogSettings.kMaxStringSizeBits}

Error message

Max inline key size is {1 << LogSettings.kMaxStringSizeBits}

What it means

SpanByteAllocator stores keys inline (no overflow key storage). PopulateRecordSizeInfo enforces keySize <= 1 << LogSettings.kMaxStringSizeBits, where kMaxStringSizeBits is 29 (512 MB). This is a hard sanity ceiling on an inline SpanByte key; in practice it only trips for a pathologically large key.

Source

Thrown at libs/storage/Tsavorite/cs/src/core/Allocator/SpanByteAllocatorImpl.cs:187

                    HasETag = false,
                    HasExpiration = false
                }
            };
            PopulateRecordSizeInfo(ref sizeInfo);
            return sizeInfo;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void PopulateRecordSizeInfo(ref RecordSizeInfo sizeInfo)
        {
            Debug.Assert(sizeInfo.word == 0, "RecordSizeInfo should not be reused");

            // For SpanByteAllocator, we are always inline.
            // Key
            sizeInfo.SetKeyIsInline();
            var keySize = sizeInfo.FieldInfo.KeySize;
            if (keySize > 1 << LogSettings.kMaxStringSizeBits)
                throw new TsavoriteException($"Max inline key size is {1 << LogSettings.kMaxStringSizeBits}");

            // Value
            sizeInfo.MaxInlineValueSize = int.MaxValue; // Not currently doing out-of-line for SpanByteAllocator
            sizeInfo.SetValueIsInline();
            var valueSize = sizeInfo.FieldInfo.ValueSize;

            // Record
            sizeInfo.CalculateSizes(keySize, valueSize);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        internal void OnDispose(ref LogRecord logRecord, DisposeReason disposeReason)
        {
            if (logRecord.IsSet)
            {
                storeFunctions.OnDispose(ref logRecord, disposeReason);

                logRecord.ClearOptionals();

View on GitHub (pinned to 951b0fc683)

Solutions

  1. Ensure keys are genuinely small identifiers (hash, GUID, fixed-width id); never use a large blob as the key.
  2. Validate key.Length against your expected maximum before the Upsert and reject oversized keys early.
  3. If keySize looks wrong relative to the bytes you supplied, suspect header/length-field corruption upstream.
  4. Reconsider the data model if you legitimately need very large keys.

Example fix

// before
session.Upsert(spanByteKey, value);

// after
const int MaxKeyBytes = 1 << 20;
if (spanByteKey.Length > MaxKeyBytes)
    throw new ArgumentException($"key too large: {spanByteKey.Length}");
session.Upsert(spanByteKey, value);
Defensive patterns

Strategy: validation

Validate before calling

const int MaxInlineKey = 1 << LogSettings.kMaxStringSizeBits; // 512 MB sanity ceiling
if (key.Length > MaxInlineKey)
    throw new ArgumentException($"key length {key.Length} exceeds inline ceiling {MaxInlineKey}");
session.Upsert(key, value);

Prevention

When it happens

Trigger: Inserting/Upserting a SpanByte key whose length exceeds 512 MB, or a record-size computation that yields such a keySize due to a miscomputed length field.

Common situations: Bug that feeds the wrong (huge) field as the key — e.g. a full document/blob used as a key; unbounded key concatenation; corrupted keySize read from a malformed record header; integer underflow producing an enormous keySize.

Related errors


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