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 RateLimitTResultSyntax.RateLimit<TResult> when numberOfExecutions is less than 1. This is the generic (TResult-returning) counterpart of the non-generic guard; a zero-execution limit would reject every call.

Source

Thrown at src/Polly/RateLimit/RateLimitTResultSyntax.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 RateLimitPolicy<TResult> RateLimit<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)

Solutions

  1. Set numberOfExecutions to at least 1.
  2. Validate the source config value before building the policy.
  3. Skip policy creation when the configured limit is not positive.

Example fix

// before
var policy = Policy.RateLimit<MyResult>(0, TimeSpan.FromSeconds(10), 5, factory);
// after
var policy = Policy.RateLimit<MyResult>(5, TimeSpan.FromSeconds(10), 5, factory);
Defensive patterns

Strategy: validation

Validate before calling

const int DefaultExecutions = 5;
var numberOfExecutions = Math.Max(1, config.GetValue("RateLimit:Executions", DefaultExecutions));
var policy = Policy.RateLimit<TResult>(numberOfExecutions, perTimeSpan, maxBurst, retryAfterFactory);

Prevention

When it happens

Trigger: Calling Policy.RateLimit<TResult>(numberOfExecutions: 0, ...) or a negative value on the generic sync overload that also takes a retryAfterFactory.

Common situations: Per-result-type rate limit built from config defaulting to 0; computed value that floors to zero.

Related errors


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