microsoft/garnet · error · TsavoriteException

{nameof(logSettings.PageSizeBits)} must be between {LogSetti

Error message

{nameof(logSettings.PageSizeBits)} must be between {LogSettings.kMinPageSizeBits} and {LogSettings.kMaxPageSizeBits}

What it means

Constructor validation: logSettings.PageSizeBits must fall in [LogSettings.kMinPageSizeBits, LogSettings.kMaxPageSizeBits] = [12, 27], i.e. page size between 4KiB and 128MiB. Pages are the unit of flush and eviction, and the bit width is baked into offset arithmetic, so out-of-range values are rejected. Default is 25 (32MiB).

Source

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

            var evictCallback = allocatorSettings.evictCallback;
            var epoch = allocatorSettings.epoch;
            var flushCallback = allocatorSettings.flushCallback;
            IsReadCache = allocatorSettings.IsReadCache;

            this.storeFunctions = storeFunctions;
            _wrapper = wrapperCreator(this);

            // Pre-bind the instance-method delegate once so the pending-IO hot path does
            // not allocate a fresh DeviceIOCompletionCallback per AsyncGetFromDisk call.
            asyncGetFromDiskCallbackDelegate = AsyncGetFromDiskCallback;

            this.transientObjectIdMap = transientObjectIdMap;

            // Validation
            if (logSettings.PageCount == 0 && logSettings.MemorySize == 0)
                throw new TsavoriteException($"{nameof(logSettings.PageCount)} or {nameof(logSettings.MemorySize)} must be specified");
            if (logSettings.PageSizeBits < LogSettings.kMinPageSizeBits || logSettings.PageSizeBits > LogSettings.kMaxPageSizeBits)
                throw new TsavoriteException($"{nameof(logSettings.PageSizeBits)} must be between {LogSettings.kMinPageSizeBits} and {LogSettings.kMaxPageSizeBits}");
            if (logSettings.PageSizeBits < PageHeader.SizeBits)
                throw new TsavoriteException($"{nameof(logSettings.PageSizeBits)} must be >= PageHeader.SizeBits {PageHeader.SizeBits}");
            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)

View on GitHub (pinned to 951b0fc683)

Solutions

  1. Set PageSizeBits to a value in [12, 27]; keep the default 25 unless you have measured a reason to change it.
  2. Remember PageSizeBits is a power-of-two exponent in BITS, not a byte count (12 => 4096 bytes).
  3. If you need very small pages for testing, use the floor 12 (4KiB); if you need huge pages, do not exceed 27.

Example fix

// before
logSettings.PageSizeBits = 10;   // intent: 1KiB pages -> below floor
// after
logSettings.PageSizeBits = 12;    // 4KiB, the minimum allowed
Defensive patterns

Strategy: validation

Validate before calling

const int MinPageBits = 12, MaxPageBits = 27; // mirror LogSettings constants
static int ClampPageSizeBits(int bits) =>
    bits < MinPageBits ? MinPageBits : bits > MaxPageBits ? MaxPageBits : bits;

logSettings.PageSizeBits = ClampPageSizeBits(logSettings.PageSizeBits);

Try / catch

try { new TsavoriteKV<K,V>(logSettings, ...); }
catch (TsavoriteException ex) when (ex.Message.Contains("PageSizeBits") && ex.Message.Contains("between"))
{ /* clamp PageSizeBits to [12,27] and recreate */ }

Prevention

When it happens

Trigger: Setting `logSettings.PageSizeBits = 10` (4KiB page desired but expressed below the floor) or `= 30` (above the 128MiB ceiling) when constructing the store.

Common situations: Confusing bits and bytes (setting PageSizeBits=4096 thinking it means 4096 bytes); tuning page size for a small-cache benchmark below the 4KiB floor; copying a config snippet written against different constants.

Related errors


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