microsoft/garnet · error · Exception

Unable to call ThreadPool.SetMinThreads with {minThreads}, {

Error message

Unable to call ThreadPool.SetMinThreads with {minThreads}, {minCPThreads}

What it means

Thrown by GarnetServer.InitializeServer when ThreadPool.SetMinThreads returns false after the user configured ThreadPoolMinThreads or ThreadPoolMinIOCompletionThreads to non-zero values. The CLR rejects min thread values that exceed the current max thread limits, or are otherwise invalid. The error message includes the attempted values for diagnosis.

Source

Thrown at libs/host/GarnetServer.cs:237

                minChanged = true;
            }
            if (opts.ThreadPoolMaxThreads > 0)
            {
                maxThreads = opts.ThreadPoolMaxThreads;
                maxChanged = true;
            }
            if (opts.ThreadPoolMaxIOCompletionThreads > 0)
            {
                maxCPThreads = opts.ThreadPoolMaxIOCompletionThreads;
                maxChanged = true;
            }

            // First try to set the max threads
            var setMax = !maxChanged || ThreadPool.SetMaxThreads(maxThreads, maxCPThreads);

            // Set the min threads
            if (minChanged && !ThreadPool.SetMinThreads(minThreads, minCPThreads))
                throw new Exception($"Unable to call ThreadPool.SetMinThreads with {minThreads}, {minCPThreads}");

            // Retry to set max threads if it wasn't set in the earlier step
            if (!setMax && !ThreadPool.SetMaxThreads(maxThreads, maxCPThreads))
                throw new Exception($"Unable to call ThreadPool.SetMaxThreads with {maxThreads}, {maxCPThreads}");

            opts.Initialize(loggerFactory);
            StoreWrapper.DatabaseCreatorDelegate createDatabaseDelegate = (int dbId) =>
                CreateDatabase(dbId, opts, clusterFactory, customCommandManager);

            if (!opts.DisablePubSub)
                subscribeBroker = new SubscribeBroker(null, opts.PubSubPageSizeBytes(), pubSubEpoch, startFresh: true, logger);

            logger?.LogTrace("TLS is {tlsEnabled}", opts.TlsOptions == null ? "disabled" : "enabled");

            // Create Garnet TCP server if none was provided.
            if (servers == null)
            {
                servers = new IGarnetServer[opts.EndPoints.Length];

View on GitHub (pinned to 951b0fc683)

Solutions

  1. Ensure ThreadPoolMinThreads <= ThreadPoolMaxThreads and ThreadPoolMinIOCompletionThreads <= ThreadPoolMaxIOCompletionThreads.
  2. If setting min threads, also set max threads to equal or higher values.
  3. Reduce the min thread values to a valid range for your environment.
  4. Check container host resource limits that may constrain the thread pool.

Example fix

// before: min exceeds default max
var opts = new GarnetServerOptions
{
    ThreadPoolMinThreads = 500  // but max is default (~32767 on most systems, or lower in containers)
};

// after: set both consistently
var opts = new GarnetServerOptions
{
    ThreadPoolMinThreads = 200,
    ThreadPoolMaxThreads = 500
};
Defensive patterns

Strategy: validation

Validate before calling

if (opts.ThreadPoolMinThreads > 0 || opts.ThreadPoolMinIOCompletionThreads > 0)
{
    ThreadPool.GetMaxThreads(out var maxWorker, out var maxIO);
    if (opts.ThreadPoolMinThreads > maxWorker)
        throw new InvalidOperationException($"Min worker threads ({opts.ThreadPoolMinThreads}) exceeds max ({maxWorker})");
    if (opts.ThreadPoolMinIOCompletionThreads > maxIO)
        throw new InvalidOperationException($"Min IO threads ({opts.ThreadPoolMinIOCompletionThreads}) exceeds max ({maxIO})");
}

Type guard

static bool AreMinThreadSettingsValid(GarnetServerOptions opts)
{
    ThreadPool.GetMaxThreads(out var maxWorker, out var maxIO);
    var minWorker = opts.ThreadPoolMinThreads > 0 ? opts.ThreadPoolMinThreads : 0;
    var minIO = opts.ThreadPoolMinIOCompletionThreads > 0 ? opts.ThreadPoolMinIOCompletionThreads : 0;
    return minWorker <= maxWorker && minIO <= maxIO;
}

Prevention

When it happens

Trigger: Setting --thread-pool-min-threads or --thread-pool-min-io-completion-threads to values that are higher than the current max thread counts, or otherwise rejected by the runtime. The CLR requires min <= max for both worker and completion port threads.

Common situations: Setting min threads higher than max threads; containerized environments where the host has restrictive thread limits; configuring min threads without also setting max threads to accommodate.

Related errors


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