App-vNext/Polly · error · ArgumentOutOfRangeException

The number of executions per timespan must be positive.

Error message

The number of executions per timespan must be positive.

What it means

Thrown by RateLimitAsync when the computed per-execution interval (perTimeSpan.Ticks / numberOfExecutions) is less than or equal to TimeSpan.Zero. Because both numberOfExecutions and perTimeSpan are already validated positive, this guard catches integer-division edge cases where perTimeSpan.Ticks is smaller than numberOfExecutions, yielding zero ticks (sub-tick intervals cannot be represented).

Source

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

        {
            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.");
        }

        IRateLimiter rateLimiter = new LockFreeTokenBucketRateLimiter(onePer, maxBurst);

        return new AsyncRateLimitPolicy(rateLimiter);
    }
}

View on GitHub (pinned to d0e46bdb1e)

Solutions

  1. Ensure perTimeSpan.Ticks >= numberOfExecutions so the per-execution interval is at least one tick; widen perTimeSpan or reduce numberOfExecutions.
  2. Reconsider the units: express the rate as executions-per-second with a one-second window.
  3. Validate the derived onePer interval before constructing the policy.
  4. If you need sub-tick granularity, the legacy LockFreeTokenBucketRateLimiter cannot represent it - use the v8 Polly.RateLimiting (System.Threading.RateLimiting) package instead.

Example fix

// before
// 1 tick / 10 executions = 0 ticks -> throws
var p = Policy.RateLimitAsync(10, TimeSpan.FromTicks(1), 10);

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

Strategy: validation

Validate before calling

if (perTimeSpan.Ticks < numberOfExecutions)
    throw new ArgumentOutOfRangeException(nameof(perTimeSpan), "perTimeSpan must have at least one tick per execution");
var p = Policy.RateLimitAsync(numberOfExecutions, perTimeSpan, maxBurst);

Prevention

When it happens

Trigger: Configuring a high numberOfExecutions against a tiny perTimeSpan such that perTimeSpan.Ticks / numberOfExecutions rounds down to zero. Example: RateLimitAsync(1000, TimeSpan.FromMilliseconds(1), burst) - 1ms is 10000 ticks, divided by 1000 = 10 ticks (ok), but TimeSpan.FromTicks(1) / 1000 = 0 ticks triggers it.

Common situations: Aggressive high-rate configs where the desired per-execution cadence is below one tick (~100ns); mis-scaled units (per-second count applied to a per-millisecond window); dynamic config that scales executions up without scaling the window.

Related errors


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