microsoft/garnet · error · TsavoriteException
{nameof(logSettings.PageSizeBits)} must be >= PageHeader.Siz
Error message
{nameof(logSettings.PageSizeBits)} must be >= PageHeader.SizeBits {PageHeader.SizeBits} What it means
Constructor validation: logSettings.PageSizeBits must be >= PageHeader.SizeBits (6, i.e. 64 bytes), because each page must be large enough to hold its header. Under the current constants this guard is shadowed by error 222 (the [12,27] range check fires first for any value below 12), so it is effectively a defensive, near-unreachable lower bound documenting the page-header constraint.
Source
Thrown at libs/storage/Tsavorite/cs/src/core/Allocator/AllocatorBase.cs:552
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)
throw new TsavoriteException($"{nameof(rcs.PageSizeBits)} must be between {LogSettings.kMinPageSizeBits} and {LogSettings.kMaxPageSizeBits}");
if (rcs.PageCount > MemoryUtils.ArrayMaxLength)View on GitHub (pinned to 951b0fc683)
Solutions
- Set PageSizeBits to at least kMinPageSizeBits (12); this automatically satisfies the PageHeader.SizeBits (6) bound.
- If maintaining a fork, keep kMinPageSizeBits >= PageHeader.SizeBits.
Example fix
// No realistic fix needed; ensure PageSizeBits >= 12 (kMinPageSizeBits). logSettings.PageSizeBits = 12;
Defensive patterns
Strategy: validation
Validate before calling
// Practically unreachable while kMinPageSizeBits (12) >= PageHeader.SizeBits (6).
// Satisfied implicitly by keeping PageSizeBits >= 12 (see error 222).
static void EnsurePageSizeAboveHeader(LogSettings s)
{
const int PageHeaderSizeBits = 6;
if (s.PageSizeBits < PageHeaderSizeBits)
throw new ArgumentException($"PageSizeBits {s.PageSizeBits} < PageHeader.SizeBits {PageHeaderSizeBits}");
} Prevention
- Treat this guard as documentation; ensure PageSizeBits >= 12 and it can never fire.
- If maintaining a fork that lowers kMinPageSizeBits, keep it >= PageHeader.SizeBits (6).
When it happens
Trigger: Only reachable if kMinPageSizeBits were ever lowered below PageHeader.SizeBits (6); today any PageSizeBits < 12 trips error 222 first. Practically unreachable with shipped constants.
Common situations: Not hit in practice on released code; a developer reading the validation chain may see it. Could surface only in a fork that lowers kMinPageSizeBits.
Related errors
- {nameof(logSettings.PageSizeBits)} must be between {LogSetti
- {nameof(logSettings.MemorySize)} must be at least {LogSettin
- {nameof(rcs.PageSizeBits)} must be between {LogSettings.kMin
- {nameof(logSettings.MemorySize)} must be at least twice the
- Segment ({SegmentSize}) must be at least of page size ({Page
AI-assisted analysis of microsoft/garnet@951b0fc683 (2026-08-13).
Data as JSON: /api/errors/f4f90762ff4c230e.
Report an issue: GitHub.