microsoft/garnet · error · TsavoriteException

{nameof(settings.LogSettings.NumberOfDeserializationBuffers)

Error message

{nameof(settings.LogSettings.NumberOfDeserializationBuffers)} must be between {LogSettings.kMinDeserializationBuffers} and {LogSettings.kMaxDeserializationBuffers - 1} and a power of 2

What it means

Thrown by ObjectAllocatorImpl when LogSettings.NumberOfDeserializationBuffers is below kMinDeserializationBuffers (2), above kMaxDeserializationBuffers (64), or not a power of two. Deserialization buffers feed the read path for object records and rely on power-of-two indexing, same constraint as flush buffers.

Source

Thrown at libs/storage/Tsavorite/cs/src/core/Allocator/ObjectAllocatorImpl.cs:93

        public ObjectAllocatorImpl(AllocatorSettings settings, TStoreFunctions storeFunctions, Func<object, ObjectAllocator<TStoreFunctions>> wrapperCreator)
            : base(settings, storeFunctions, wrapperCreator, settings.logger, transientObjectIdMap: new ObjectIdMap())
        {
            objectLogDevice = settings.LogSettings.ObjectLogDevice;

            maxInlineKeySize = settings.LogSettings.MaxInlineKeySize;
            maxInlineValueSize = settings.LogSettings.MaxInlineValueSize;

            ObjectLogSegmentSize = 1L << settings.LogSettings.ObjectLogSegmentSizeBits;

            freePagePool = new OverflowPool<PageUnit<ObjectPage>>(4, static p => { });
            pageHeaderSize = PageHeader.Size;

            if (settings.LogSettings.NumberOfFlushBuffers < LogSettings.kMinFlushBuffers || settings.LogSettings.NumberOfFlushBuffers > LogSettings.kMaxFlushBuffers || !IsPowerOfTwo(settings.LogSettings.NumberOfFlushBuffers))
                throw new TsavoriteException($"{nameof(settings.LogSettings.NumberOfFlushBuffers)} must be between {LogSettings.kMinFlushBuffers} and {LogSettings.kMaxFlushBuffers - 1} and a power of 2");
            numberOfFlushBuffers = settings.LogSettings.NumberOfFlushBuffers;

            if (settings.LogSettings.NumberOfDeserializationBuffers < LogSettings.kMinDeserializationBuffers || settings.LogSettings.NumberOfDeserializationBuffers > LogSettings.kMaxDeserializationBuffers || !IsPowerOfTwo(settings.LogSettings.NumberOfDeserializationBuffers))
                throw new TsavoriteException($"{nameof(settings.LogSettings.NumberOfDeserializationBuffers)} must be between {LogSettings.kMinDeserializationBuffers} and {LogSettings.kMaxDeserializationBuffers - 1} and a power of 2");
            numberOfDeserializationBuffers = settings.LogSettings.NumberOfDeserializationBuffers;

            if (settings.LogSettings.ObjectLogSegmentSizeBits is < LogSettings.kMinObjectLogSegmentSizeBits or > LogSettings.kMaxSegmentSizeBits)
                throw new TsavoriteException($"{nameof(settings.LogSettings.ObjectLogSegmentSizeBits)} must be between {LogSettings.kMinObjectLogSegmentSizeBits} and {LogSettings.kMaxSegmentSizeBits}");
            objectLogTail = new(0, settings.LogSettings.ObjectLogSegmentSizeBits);

            objectPages = new ObjectPage[BufferSize];
            for (var ii = 0; ii < BufferSize; ii++)
                objectPages[ii] = new();
        }

        /// <summary>Initialize allocator</summary>
        [MethodImpl(MethodImplOptions.NoInlining)]
        protected internal override void Initialize()
        {
            base.Initialize();
            LastIssuedFlushedUntilAddress = FlushedUntilAddress;
            OngoingFlushedUntilAddress = 0;

View on GitHub (pinned to 951b0fc683)

Solutions

  1. Set NumberOfDeserializationBuffers to a power of two in [2, 64].
  2. Round any heuristic value up to the next power of two and clamp to the range.
  3. Keep the default (4) unless read-path object deserialization is a measured bottleneck.

Example fix

// before
logSettings.NumberOfDeserializationBuffers = 6; // not a power of 2
// after
logSettings.NumberOfDeserializationBuffers = 8;
Defensive patterns

Strategy: validation

Validate before calling

static bool IsValidDeserBuffers(int n) =>
    n >= LogSettings.kMinDeserializationBuffers && n <= LogSettings.kMaxDeserializationBuffers && (n & (n - 1)) == 0;
if (!IsValidDeserBuffers(logSettings.NumberOfDeserializationBuffers))
    throw new ArgumentException($"NumberOfDeserializationBuffers must be a power of two in [2,64]");

Prevention

When it happens

Trigger: Setting LogSettings.NumberOfDeserializationBuffers to a non-power-of-two, < 2, or > 64, then constructing an object-backed store. Default is 4.

Common situations: Mirroring NumberOfFlushBuffers to a non-power-of-two value; sizing deserialization buffers to CPU count or thread count directly; inheriting a config from a version that validated less strictly.

Related errors


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