App-vNext/Polly · error · ArgumentOutOfRangeException

numberOfExecutions per timespan must be an integer greater t

Error message

numberOfExecutions per timespan must be an integer greater than or equal to 1.

What it means

Thrown by RateLimitAsync(int, TimeSpan, int) (the factory-less overload) when numberOfExecutions is less than 1. numberOfExecutions defines how many executions are permitted per perTimeSpan window, so zero or negative values are meaningless. The guard is the first of three sequential config validations.

Source

Thrown at src/Polly/RateLimit/AsyncRateLimitSyntax.cs:32

        TimeSpan perTimeSpan) =>
        RateLimitAsync(numberOfExecutions, perTimeSpan, 1);

    /// <summary>
    /// Builds a RateLimit <see cref="AsyncPolicy"/> that will rate-limit executions to <paramref name="numberOfExecutions"/> per the timespan given.
    /// </summary>
    /// <param name="numberOfExecutions">The number of executions (call it N) permitted per timespan.</param>
    /// <param name="perTimeSpan">How often N executions are permitted.</param>
    /// <param name="maxBurst">The maximum number of executions that will be permitted in a single burst (for example if none have been executed for a while).
    /// This equates to the bucket-capacity of a token-bucket implementation.</param>
    /// <returns>The policy instance.</returns>
    public static AsyncRateLimitPolicy RateLimitAsync(
        int numberOfExecutions,
        TimeSpan perTimeSpan,
        int maxBurst)
    {
        if (numberOfExecutions < 1)
        {
            throw new ArgumentOutOfRangeException(nameof(numberOfExecutions), numberOfExecutions, $"{nameof(numberOfExecutions)} per timespan must be an integer greater than or equal to 1.");
        }

        if (perTimeSpan <= TimeSpan.Zero)
        {
            throw new ArgumentOutOfRangeException(nameof(perTimeSpan), perTimeSpan, $"{nameof(perTimeSpan)} must be a positive timespan.");
        }

        if (maxBurst < 1)
        {
            throw new ArgumentOutOfRangeException(nameof(maxBurst), maxBurst, $"{nameof(maxBurst)} must be an integer greater than or equal to 1.");
        }

        var onePer = TimeSpan.FromTicks(perTimeSpan.Ticks / numberOfExecutions);

        if (onePer <= TimeSpan.Zero)
        {
            throw new ArgumentOutOfRangeException(nameof(perTimeSpan), perTimeSpan, "The number of executions per timespan must be positive.");
        }

View on GitHub (pinned to d0e46bdb1e)

Solutions

  1. Set numberOfExecutions to a positive integer that reflects measured throughput, e.g. 100.
  2. Validate/clamp the config value before passing it: Math.Max(1, parsedValue).
  3. Distinguish 'disable rate limiting' (do not create the policy at all) from 'zero executions'.
  4. Add an integration test that constructs the policy with realistic config to catch bad values early.

Example fix

// before
var p = Policy.RateLimitAsync(0, TimeSpan.FromSeconds(1), 10);

// after
var p = Policy.RateLimitAsync(10, TimeSpan.FromSeconds(1), 10);
Defensive patterns

Strategy: validation

Validate before calling

int n = Math.Max(1, parsedNumberOfExecutions);
if (n < 1) throw new ArgumentOutOfRangeException(nameof(n));
var p = Policy.RateLimitAsync(n, perTimeSpan, maxBurst);

Prevention

When it happens

Trigger: Calling Policy.RateLimitAsync(0, ts, burst) or with a negative numberOfExecutions. Common when the value is derived from configuration without clamping.

Common situations: Reading numberOfExecutions from appsettings/environment where it is missing (parses to 0), mis-scaled units (per-second value used as per-minute), or a feature flag disabling a limit by setting it to 0.

Related errors


AI-assisted analysis of App-vNext/Polly@d0e46bdb1e (2026-08-13). Data as JSON: /api/errors/373e072803941eda. Report an issue: GitHub.