microsoft/garnet · error · TsavoriteException

{nameof(rcs.PageCount)} must be less than or equal to the ma

Error message

{nameof(rcs.PageCount)} must be less than or equal to the maximum array length ({MemoryUtils.ArrayMaxLength})

What it means

Constructor validation for the read cache: rcs.PageCount must not exceed MemoryUtils.ArrayMaxLength (0x7FFFFFC7 = 2,147,483,591), for the same array-backed ring reason as the main log (error 224).

Source

Thrown at libs/storage/Tsavorite/cs/src/core/Allocator/AllocatorBase.cs:571

            if (logSettings.PageCount > MemoryUtils.ArrayMaxLength)
                throw new TsavoriteException($"{nameof(logSettings.PageCount)} must be less than or equal to the maximum array length ({MemoryUtils.ArrayMaxLength})");
            if (logSettings.SegmentSizeBits < LogSettings.kMinMainLogSegmentSizeBits || logSettings.SegmentSizeBits > LogSettings.kMaxSegmentSizeBits)
                throw new TsavoriteException($"{nameof(logSettings.SegmentSizeBits)} must be between {LogSettings.kMinMainLogSegmentSizeBits} and {LogSettings.kMaxSegmentSizeBits}");
            if (logSettings.MemorySize != 0 && (logSettings.MemorySize < 1L << LogSettings.kMinMemorySizeBits || logSettings.MemorySize > 1L << LogSettings.kMaxMemorySizeBits))
                throw new TsavoriteException($"{nameof(logSettings.MemorySize)} must be between {1L << LogSettings.kMinMemorySizeBits} and {1L << LogSettings.kMaxMemorySizeBits}, or may be 0 for ReadOnly TsavoriteLog");
            if ((logSettings.MemorySize != 0) && (logSettings.MemorySize < (1L << logSettings.PageSizeBits) * LogSettings.kMinPageCount))
                throw new TsavoriteException($"{nameof(logSettings.MemorySize)} must be at least {LogSettings.kMinPageCount}x the page size ({1L << logSettings.PageSizeBits})");
            if (logSettings.MutableFraction < 0.0 || logSettings.MutableFraction > 1.0)
                throw new TsavoriteException($"{nameof(logSettings.MutableFraction)} must be >= 0.0 and <= 1.0");
            if (logSettings.ReadCacheSettings is not null)
            {
                var rcs = logSettings.ReadCacheSettings;
                if (rcs.PageCount == 0 && rcs.MemorySize == 0)
                    throw new TsavoriteException($"{nameof(rcs.PageCount)} or {nameof(rcs.MemorySize)} must be specified");
                if (rcs.PageSizeBits < LogSettings.kMinPageSizeBits || rcs.PageSizeBits > LogSettings.kMaxPageSizeBits)
                    throw new TsavoriteException($"{nameof(rcs.PageSizeBits)} must be between {LogSettings.kMinPageSizeBits} and {LogSettings.kMaxPageSizeBits}");
                if (rcs.PageCount > MemoryUtils.ArrayMaxLength)
                    throw new TsavoriteException($"{nameof(rcs.PageCount)} must be less than or equal to the maximum array length ({MemoryUtils.ArrayMaxLength})");
                if (rcs.MemorySize != 0 && (rcs.MemorySize < 1L << LogSettings.kMinMemorySizeBits || rcs.MemorySize > 1L << LogSettings.kMaxMemorySizeBits))
                    throw new TsavoriteException($"{nameof(rcs.MemorySize)} must be between {1L << LogSettings.kMinMemorySizeBits} and {1L << LogSettings.kMaxMemorySizeBits}");
                if ((rcs.MemorySize != 0) && (rcs.MemorySize < (1L << rcs.PageSizeBits) * 2))
                    throw new TsavoriteException($"{nameof(logSettings.MemorySize)} must be at least twice the page size ({1L << rcs.PageSizeBits})");
                if (rcs.SecondChanceFraction < 0.0 || rcs.SecondChanceFraction > 1.0)
                    throw new TsavoriteException($"{rcs.SecondChanceFraction} must be >= 0.0 and <= 1.0");
            }

            if (logSettings.MaxInlineKeySize < LogSettings.MinMaxInlineSize || logSettings.MaxInlineKeySize > LogSettings.MaxInlineKeySizeLimit)
                throw new TsavoriteException($"{nameof(logSettings.MaxInlineKeySize)} must be between {LogSettings.MinMaxInlineSize} and {LogSettings.MaxInlineKeySizeLimit}");
            if (logSettings.MaxInlineValueSize < LogSettings.MinMaxInlineSize || logSettings.MaxInlineValueSize > LogSettings.MaxInlineValueSizeLimit)
                throw new TsavoriteException($"{nameof(logSettings.MaxInlineValueSize)} must be between {LogSettings.MinMaxInlineSize} and {LogSettings.MaxInlineValueSizeLimit}");

            this.logger = logger;
            if (logSettings.LogDevice == null)
                throw new TsavoriteException("LogSettings.LogDevice needs to be specified (e.g., use Devices.CreateLogDevice, AzureStorageDevice, or NullDevice)");

            EvictCallback = evictCallback;

View on GitHub (pinned to 951b0fc683)

Solutions

  1. Keep rcs.PageCount well below 0x7FFFFFC7 (a few hundred to thousand pages is typical).
  2. Prefer sizing the read cache via MemorySize and let PageCount be derived.
  3. Validate/clamp the config-sourced value before assignment.

Example fix

// before
rcs.PageCount = int.MaxValue;
// after
rcs.MemorySize = 1L << 26;  // 64MiB; leave PageCount to derive
Defensive patterns

Strategy: validation

Validate before calling

const int ArrayMaxLength = 0x7FFFFFC7;
if (logSettings.ReadCacheSettings is { } rcs && rcs.PageCount > ArrayMaxLength)
    throw new ArgumentOutOfRangeException(nameof(rcs.PageCount),
        $"ReadCache PageCount {rcs.PageCount} exceeds ArrayMaxLength");

Try / catch

try { new TsavoriteKV<K,V>(logSettings, ...); }
catch (TsavoriteException ex) when (ex.Message.Contains("rcs.PageCount") && ex.Message.Contains("maximum array length"))
{ /* reduce read-cache PageCount or size via MemorySize */ }

Prevention

When it happens

Trigger: Setting ReadCacheSettings.PageCount to an extreme value (e.g. int.MaxValue) when enabling the read cache.

Common situations: Sizing the read cache from an unbounded config value; unit confusion producing billions of pages.

Related errors


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