microsoft/garnet · error · TsavoriteException

{nameof(logSettings.MutableFraction)} must be >= 0.0 and <=

Error message

{nameof(logSettings.MutableFraction)} must be >= 0.0 and <= 1.0

What it means

Constructor validation: logSettings.MutableFraction must be in [0.0, 1.0]. MutableFraction bounds the fraction of the in-memory log eligible for in-place updates; outside [0,1] it is meaningless. Default is 0.9.

Source

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

            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)
                    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)

View on GitHub (pinned to 951b0fc683)

Solutions

  1. Clamp MutableFraction to [0.0, 1.0] before assigning; keep the default 0.9 unless you have a measured reason.
  2. If your config uses percentages, divide by 100.0.
  3. Guard against NaN/explicitly default when config parsing fails.

Example fix

// before
logSettings.MutableFraction = 90;        // meant 90%, actually 9000%
// after
logSettings.MutableFraction = 0.9;       // or: parsedPct / 100.0
Defensive patterns

Strategy: validation

Validate before calling

static double ClampFraction(double f) =>
    double.IsNaN(f) ? 0.9 : f < 0.0 ? 0.0 : f > 1.0 ? 1.0 : f;

logSettings.MutableFraction = ClampFraction(logSettings.MutableFraction);

Try / catch

try { new TsavoriteKV<K,V>(logSettings, ...); }
catch (TsavoriteException ex) when (ex.Message.Contains("MutableFraction"))
{ /* clamp MutableFraction to [0,1] and recreate */ }

Prevention

When it happens

Trigger: Setting `logSettings.MutableFraction = 1.2`, `-0.1`, or `double.NaN` (NaN compares false to both bounds, so it trips the > 1.0 clause).

Common situations: Loading a fraction from config without clamping; accidental integer/percentage confusion (passing 90 meaning 90%); NaN from a failed parse.

Related errors


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