microsoft/garnet · critical · Exception

AofMemorySize (effective {effectiveMemory} after rounding do

Error message

AofMemorySize (effective {effectiveMemory} after rounding down to a power of two) must be at least twice AofPageSize (effective {effectivePage}). Increase --aof-memory to at least {minMemory}, or reduce --aof-page-size.

What it means

Garnet validates that the AOF (Append-Only File) in-memory buffer is at least twice the AOF page size, because Tsavorite's hybrid log requires a minimum of two pages resident in memory. The check uses log2 bit values: memorySizeBits <= pageSizeBits means the effective memory is less than 2× the page. If violated, the server aborts startup before allocating any device or commit manager.

Source

Thrown at libs/server/Servers/GarnetServerOptions.cs:987

            var memorySizeBits = AofMemorySizeBits();
            var pageSizeBits = AofPageSizeBits();
            var segmentSizeBits = AofSegmentSizeBits();

            // Tsavorite requires MemorySize >= 2 * PageSize (so at least two pages fit in memory).
            // With power-of-two rounded sizes this means memorySizeBits >= pageSizeBits + 1.
            // Catch this here so we can produce a Garnet-specific error that names the actual
            // AofMemorySize / AofPageSize config options, rather than the generic Tsavorite
            // "MemorySize must be at least twice the page size" message which does not say AOF.
            if (memorySizeBits <= pageSizeBits)
            {
                var effectiveMemory = PrettySize(1L << memorySizeBits);
                var effectivePage = PrettySize(1L << pageSizeBits);
                var minMemory = PrettySize(1L << (pageSizeBits + 1));
                var msg = $"AofMemorySize (effective {effectiveMemory} after rounding down to a power of two) " +
                          $"must be at least twice AofPageSize (effective {effectivePage}). " +
                          $"Increase --aof-memory to at least {minMemory}, or reduce --aof-page-size.";
                logger?.LogError("{msg}", msg);
                throw new Exception(msg);
            }

            if (pageSizeBits > segmentSizeBits)
            {
                var effectivePage = PrettySize(1L << pageSizeBits);
                var effectiveSegment = PrettySize(1L << segmentSizeBits);
                var msg = $"AofPageSize (effective {effectivePage} after rounding down to a power of two) " +
                          $"cannot be larger than AofSegmentSize (effective {effectiveSegment}). " +
                          $"Increase --aof-segment-size to at least {effectivePage}, or reduce --aof-page-size.";
                logger?.LogError("{msg}", msg);
                throw new Exception(msg);
            }

            // AofPageSize must be at least twice the main-log PageSize. An AOF entry mirrors a single
            // main-log write (key + value/input + small overhead); raw-string SETs can be as large as
            // the main-log PageSize (values above MaxInlineValueSize overflow to the heap on the main
            // store but are still written in full to the AOF), and object commands like LPUSH/HSET can
            // push the AOF entry even higher. Throw a clear error here so users do not hit the runtime

View on GitHub (pinned to 951b0fc683)

Solutions

  1. Increase --aof-memory to at least twice the effective --aof-page-size (e.g. if page is 32m, set memory to 64m).
  2. Reduce --aof-page-size so that the existing --aof-memory is at least double it.
  3. Remove explicit --aof-page-size and --aof-memory overrides entirely to use Garnet's safe defaults.

Example fix

// before
--aof-memory 32m --aof-page-size 32m

// after
--aof-memory 64m --aof-page-size 32m
Defensive patterns

Strategy: validation

Validate before calling

// Validate before starting the server
var memBits = options.AofMemorySizeBits();
var pageBits = options.AofPageSizeBits();
if (memBits <= pageBits)
    throw new InvalidOperationException($"AOF memory ({1L << memBits} bytes) must be at least twice AOF page size ({1L << pageBits} bytes).");

Try / catch

// Wrap GetAofSettings in startup validation
try { options.GetAofSettings(dbId, out var settings); }
catch (Exception ex) when (ex.Message.Contains("AofMemorySize"))
{ logger.LogError("AOF config invalid: {Msg}. Fix --aof-memory or --aof-page-size.", ex.Message); throw; }

Prevention

When it happens

Trigger: Calling GetAofSettings() when AofMemorySizeBits() <= AofPageSizeBits(). Occurs when --aof-memory (after power-of-two rounding) is less than 2× --aof-page-size. For example, --aof-memory 32m --aof-page-size 32m produces memorySizeBits == pageSizeBits.

Common situations: Copying a config template that sets --aof-page-size high without proportionally raising --aof-memory; upgrading Garnet versions where AOF defaults changed; tuning AOF page size for write throughput and forgetting the memory must be at least double.

Related errors


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