microsoft/garnet · error · TsavoriteException
{rcs.SecondChanceFraction} must be >= 0.0 and <= 1.0
Error message
{rcs.SecondChanceFraction} must be >= 0.0 and <= 1.0 What it means
Constructor validation for the read cache: rcs.SecondChanceFraction must be in [0.0, 1.0]. It controls the fraction of read-cache pages given a second chance during eviction. Note the message interpolates the raw value (`{rcs.SecondChanceFraction}`) rather than the field name, so the exception text shows a number, not 'SecondChanceFraction'.
Source
Thrown at libs/storage/Tsavorite/cs/src/core/Allocator/AllocatorBase.cs:577
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)
throw new TsavoriteException($"{nameof(logSettings.MaxInlineKeySize)} must be between {LogSettings.MinMaxInlineSize} and {LogSettings.MaxInlineKeySizeLimit}");
if (logSettings.MaxInlineValueSize < LogSettings.MinMaxInlineSize || logSettings.MaxInlineValueSize > LogSettings.MaxInlineValueSizeLimit)
throw new TsavoriteException($"{nameof(logSettings.MaxInlineValueSize)} must be between {LogSettings.MinMaxInlineSize} and {LogSettings.MaxInlineValueSizeLimit}");
this.logger = logger;
if (logSettings.LogDevice == null)
throw new TsavoriteException("LogSettings.LogDevice needs to be specified (e.g., use Devices.CreateLogDevice, AzureStorageDevice, or NullDevice)");
EvictCallback = evictCallback;
FlushCallback = flushCallback;
PreallocateLog = logSettings.PreallocateLog;
flushEvent.Initialize();
IsNullDevice = logSettings.LogDevice is NullDevice;View on GitHub (pinned to 951b0fc683)
Solutions
- Clamp SecondChanceFraction to [0.0, 1.0] before assigning (typical: 0.5).
- If config uses percentages, divide by 100.0.
- Default the value when config parsing produces NaN.
Example fix
// before rcs.SecondChanceFraction = 50; // meant 50% // after rcs.SecondChanceFraction = 0.5;
Defensive patterns
Strategy: validation
Validate before calling
static double ClampFraction(double f) =>
double.IsNaN(f) ? 0.5 : f < 0.0 ? 0.0 : f > 1.0 ? 1.0 : f;
if (logSettings.ReadCacheSettings is { } rcs)
rcs.SecondChanceFraction = ClampFraction(rcs.SecondChanceFraction); Try / catch
try { new TsavoriteKV<K,V>(logSettings, ...); }
catch (TsavoriteException ex) when (ex.Message.Contains("SecondChanceFraction") || ex.Message.Contains("must be >= 0.0 and <= 1.0"))
{ /* NOTE: message shows the numeric value, not the field name; clamp rcs.SecondChanceFraction to [0,1] */ } Prevention
- The exception text shows the offending number (e.g. '1.2 must be >= 0.0...'), not the field name — grep your config for the value.
- Clamp read-cache fractions from config and handle NaN.
- Default SecondChanceFraction to ~0.5 when unsure.
When it happens
Trigger: Setting ReadCacheSettings.SecondChanceFraction outside [0,1], including NaN (NaN trips the > 1.0 comparison).
Common situations: Loading the fraction from config without clamping; percentage confusion (passing 50 for 50%); NaN from a parse failure.
Related errors
- {nameof(logSettings.MemorySize)} must be at least twice the
- {nameof(rcs.PageCount)} or {nameof(rcs.MemorySize)} must be
- {nameof(rcs.PageSizeBits)} must be between {LogSettings.kMin
- {nameof(rcs.PageCount)} must be less than or equal to the ma
- {nameof(rcs.MemorySize)} must be between {1L << LogSettings.
AI-assisted analysis of microsoft/garnet@951b0fc683 (2026-08-13).
Data as JSON: /api/errors/235f46946656f26e.
Report an issue: GitHub.