App-vNext/Polly · error · ArgumentOutOfRangeException
Value must be greater than or equal to zero.
Error message
Value must be greater than or equal to zero.
What it means
This generic Retry<TResult> overload (RetryTResultSyntax.cs:54) throws ArgumentOutOfRangeException synchronously when retryCount is negative. The guard `retryCount < 0` enforces a valid attempt budget for the result-typed retry policy at construction time.
Source
Thrown at src/Polly/Retry/RetryTResultSyntax.cs:54
public static RetryPolicy<TResult> Retry<TResult>(this PolicyBuilder<TResult> policyBuilder, Action<DelegateResult<TResult>, int> onRetry) =>
policyBuilder.Retry(1, onRetry);
/// <summary>
/// Builds a <see cref="Policy{TResult}"/> that will retry <paramref name="retryCount"/> times
/// calling <paramref name="onRetry"/> on each retry with the handled exception or result and retry count.
/// </summary>
/// <typeparam name="TResult">The type of the result.</typeparam>
/// <param name="policyBuilder">The policy builder.</param>
/// <param name="retryCount">The retry count.</param>
/// <param name="onRetry">The action to call on each retry.</param>
/// <returns>The policy instance.</returns>
/// <exception cref="ArgumentOutOfRangeException">retryCount;Value must be greater than or equal to zero.</exception>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="onRetry"/> is <see langword="null"/>.</exception>
public static RetryPolicy<TResult> Retry<TResult>(this PolicyBuilder<TResult> policyBuilder, int retryCount, Action<DelegateResult<TResult>, int> onRetry)
{
if (retryCount < 0)
{
throw new ArgumentOutOfRangeException(nameof(retryCount), "Value must be greater than or equal to zero.");
}
if (onRetry == null)
{
throw new ArgumentNullException(nameof(onRetry));
}
return policyBuilder.Retry(retryCount, (outcome, i, _) => onRetry(outcome, i));
}
/// <summary>
/// Builds a <see cref="Policy{TResult}"/> that will retry once
/// calling <paramref name="onRetry"/> on retry with the handled exception or result, retry count and context data.
/// </summary>
/// <typeparam name="TResult">The type of the result.</typeparam>
/// <param name="policyBuilder">The policy builder.</param>
/// <param name="onRetry">The action to call on each retry.</param>
/// <returns>The policy instance.</returns>View on GitHub (pinned to d0e46bdb1e)
Solutions
- Pass retryCount >= 0 (0 means no retries).
- Clamp config-sourced values with Math.Max(0, value).
- Trace where the negative value originates.
Example fix
// before var policy = Policy.HandleResult<int>(r => r < 0).Retry(-1, onRetry); // after var retryCount = Math.Max(0, configuredRetries); var policy = Policy.HandleResult<int>(r => r < 0).Retry(retryCount, onRetry);
Defensive patterns
Strategy: validation
Validate before calling
if (retryCount < 0) throw new ArgumentOutOfRangeException(nameof(retryCount)); var clamped = Math.Max(0, retryCount); var policy = Policy.HandleResult<int>(r => r < 0).Retry(clamped, onRetry);
Prevention
- Clamp config-sourced retry counts with Math.Max(0, value).
- Reject negative retry counts at config-bind time.
- Unit-test policy construction with boundary retry counts (0, 1, large).
When it happens
Trigger: Calling Policy.HandleResult<T>(...).Retry(retryCount, onRetry) where retryCount is negative, with onRetry typed Action<DelegateResult<TResult>, int>.
Common situations: Computed retry count that underflows (e.g. configured - 1 where configured is 0); a config value defaulting to -1; sentinel misuse.
Related errors
- sleepDurations
- onRetry
- Value must be greater than zero.
- Value must be greater than or equal to zero.
- Value must be greater than zero.
AI-assisted analysis of App-vNext/Polly@d0e46bdb1e (2026-08-13).
Data as JSON: /api/errors/81105684af6045b2.
Report an issue: GitHub.