App-vNext/Polly · error · ArgumentOutOfRangeException
perTimeSpan must be a positive timespan.
Error message
perTimeSpan must be a positive timespan.
What it means
Thrown by RateLimitAsync when perTimeSpan is less than or equal to TimeSpan.Zero. perTimeSpan defines the refill window for the token bucket; a non-positive window breaks the bucket math. The guard runs after the numberOfExecutions check.
Source
Thrown at src/Polly/RateLimit/AsyncRateLimitSyntax.cs:37
/// </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.");
}
IRateLimiter rateLimiter = new LockFreeTokenBucketRateLimiter(onePer, maxBurst);
return new AsyncRateLimitPolicy(rateLimiter);
}View on GitHub (pinned to d0e46bdb1e)
Solutions
- Provide a positive TimeSpan, e.g. TimeSpan.FromSeconds(1).
- Validate the config value: if (perTimeSpan <= TimeSpan.Zero) throw; before constructing the policy.
- Confirm the unit conversion (ticks/ms/s) of the source setting.
- Default optional config to a sane positive value rather than default(TimeSpan).
Example fix
// before var p = Policy.RateLimitAsync(10, TimeSpan.Zero, 10); // after var p = Policy.RateLimitAsync(10, TimeSpan.FromSeconds(1), 10);
Defensive patterns
Strategy: validation
Validate before calling
if (perTimeSpan <= TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(perTimeSpan)); var p = Policy.RateLimitAsync(n, perTimeSpan, maxBurst);
Prevention
- Confirm the unit (ticks/ms/s) of the source config value.
- Default optional perTimeSpan to a known positive value, not default(TimeSpan).
- Validate the full config triple at startup.
When it happens
Trigger: Calling Policy.RateLimitAsync(n, TimeSpan.Zero, burst) or with a negative TimeSpan. Also hit when perTimeSpan comes from a misconfigured duration (zero ticks) or a subtraction that underflows.
Common situations: Configuring perTimeSpan from a numeric setting interpreted with the wrong unit (e.g. ms vs s) producing zero; default(TimeSpan) passed inadvertently; environment-driven window that is unset.
Related errors
- The number of executions per timespan must be positive.
- perTimeSpan must be a positive timespan.
- The number of executions per timespan must be positive.
- numberOfExecutions per timespan must be an integer greater t
- maxBurst must be an integer greater than or equal to 1.
AI-assisted analysis of App-vNext/Polly@d0e46bdb1e (2026-08-13).
Data as JSON: /api/errors/e8c512ac2abc7f7e.
Report an issue: GitHub.