dotnet/machinelearning · error · ArgumentOutOfRangeException

Cache size must be a positive number.

Error message

Cache size must be a positive number.

What it means

The LruCache constructor validates cacheSize and throws ArgumentOutOfRangeException when it is zero or negative, since the cache must be able to hold at least one entry. This is an eager constructor guard so bad configuration fails at construction time rather than at first use.

Solutions

  1. Pass a positive cache size, e.g. Math.Max(1, configuredSize) or the DefaultCacheSize (8192).
  2. Fix config parsing so a missing CacheSize value falls back to DefaultCacheSize instead of 0.
  3. Validate configuration values at startup, before constructing the cache.
  4. Guard: if (size <= 0) size = LruCache.DefaultCacheSize; at the call site.

Example fix

// before
int size = int.TryParse(config["CacheSize"], out var s) ? s : 0;
var cache = new LruCache<string>(size);
// after
int size = int.TryParse(config["CacheSize"], out var s) && s > 0 ? s : LruCache<int>.DefaultCacheSize;
var cache = new LruCache<string>(size);
Defensive patterns

Strategy: validation

Validate before calling

if (cacheSize <= 0) cacheSize = LruCache<string>.DefaultCacheSize;
var cache = new LruCache<string>(cacheSize);

Type guard

static bool IsValidCacheSize(int size) => size > 0;

Try / catch

try { cache = new LruCache<string>(configuredSize); }
catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "cacheSize")
{ cache = new LruCache<string>(); } // fall back to default

Prevention

When it happens

Trigger: Constructing LruCache<TValue>(cacheSize) with cacheSize <= 0 — typically from a config value read as 0 when a setting is missing/unparsed, or code doing maxEntries - something that underflows to a negative number.

Common situations: An app setting like CacheSize read from an empty/invalid config value defaulting to 0, an int.Parse of a non-numeric string coerced to 0, or arithmetic producing negative capacity.

Related errors


AI-assisted analysis of dotnet/machinelearning@7b76e69cf9 (2026-09-11). Data as JSON: /api/errors/2f711672780d677a. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.ML.Tokenizers/Utils/LruCache.cs:33

        public const int DefaultCacheSize = 8192;

        private readonly Dictionary<StringSpanOrdinalKey, LinkedListNode<KeyValuePair<string, TValue>>> _cache = new();
        private readonly LinkedList<KeyValuePair<string, TValue>> _lruList = new();
        private readonly int _cacheSize;

        private object SyncObj => _cache;

        /// <summary>
        /// Constructs an <see cref="LruCache{TValue}" /> object.
        /// </summary>
        /// <param name="cacheSize">
        /// The maximum number of mappings that can be cached. This defaults to <see cref="DefaultCacheSize" />, which is set to <value>8192</value>.
        /// </param>
        public LruCache(int cacheSize = DefaultCacheSize)
        {
            if (cacheSize <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(cacheSize), "Cache size must be a positive number.");
            }

            _cacheSize = cacheSize;
        }

        /// <summary>
        /// Retrieves the value associated with the specified key /> object.
        /// </summary>
        /// <param name="key">The object to be used as a key.</param>
        /// <param name="value">An out parameter that is set to the value of the key if key contains a mapping in the cache.</param>
        /// <returns>
        /// true if the cache contains a mapping for key, false otherwise.
        /// </returns>
        public bool TryGetValue(string key, out TValue value)
        {
            lock (SyncObj)
            {
                if (_cache.TryGetValue(new StringSpanOrdinalKey(key), out LinkedListNode<KeyValuePair<string, TValue>>? cached))

View on GitHub (pinned to 7b76e69cf9)