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
- Set NumberOfDeserializationBuffers to a power of two in [2, 64].
- Round any heuristic value up to the next power of two and clamp to the range.
- 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
- Round any heuristic buffer count up to the next power of two and clamp to [2,64].
- Validate all LogSettings fields once at startup rather than discovering failures at construction.
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
- Expected start of JSON object.
- {nameof(settings.LogSettings.NumberOfFlushBuffers)} must be
- {nameof(settings.LogSettings.ObjectLogSegmentSizeBits)} must
- Invalid ClusterConfig payload: too short to contain a versio
- Unable to deserialize RedisOptions object. Line {lineCount}
AI-assisted analysis of microsoft/garnet@951b0fc683 (2026-08-13).
Data as JSON: /api/errors/c08d7a3798dd0a50.
Report an issue: GitHub.