App-vNext/Polly · error · ArgumentOutOfRangeException

numberOfExecutions per timespan must be an integer greater…

Error message

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

What it means

Thrown by the typed RateLimitAsync<TResult>(int, TimeSpan, int, Func<TimeSpan,Context,TResult>?) overload when numberOfExecutions is less than 1. Identical validation to the factory-less overload; the typed (TResult-locked) policy applies the same lower bound on executions per window.

Solutions

  1. Set numberOfExecutions to a positive integer matching measured load.
  2. Clamp config: Math.Max(1, parsed); reject non-positive values at the config layer.
  3. To disable rate limiting, skip policy construction rather than passing 0.
  4. Add a config validation step at startup that asserts all three numeric bounds.

Example fix

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

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

Strategy: validation

Validate before calling

int n = Math.Max(1, parsedNumberOfExecutions);
var p = Policy.RateLimitAsync<TResult>(n, perTimeSpan, maxBurst, retryAfterFactory);

Prevention

When it happens

Trigger: Calling Policy.RateLimitAsync<TResult>(0, ts, burst, factory) or with a negative numberOfExecutions. The factory argument does not affect this guard.

Common situations: Config-driven numberOfExecutions that parses to 0 (missing key), a feature flag setting the limit to 0 to 'disable', or mis-scaled units from configuration.

Related errors


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

Appendix: source

Thrown at src/Polly/RateLimit/AsyncRateLimitTResultSyntax.cs:68

    /// with a maximum burst size of <paramref name="maxBurst"/>.
    /// </summary>
    /// <typeparam name="TResult">The type of return values this policy will handle.</typeparam>
    /// <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>
    /// <param name="retryAfterFactory">An (optional) factory to use to express retry-after back to the caller, when an operation is rate-limited.
    /// <remarks>If null, a <see cref="RateLimitRejectedException"/> with property <see cref="RateLimitRejectedException.RetryAfter"/> will be thrown to indicate rate-limiting.</remarks></param>
    /// <returns>The policy instance.</returns>
    public static AsyncRateLimitPolicy<TResult> RateLimitAsync<TResult>(
        int numberOfExecutions,
        TimeSpan perTimeSpan,
        int maxBurst,
        Func<TimeSpan, Context, TResult>? retryAfterFactory)
    {
        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)