App-vNext/Polly · error · ArgumentNullException
onRetry
Error message
onRetry
What it means
This generic Retry<TResult> overload (RetryTResultSyntax.cs:59) throws ArgumentNullException when onRetry is null. The callback Action<DelegateResult<TResult>, int> reports each retry's handled result/exception and attempt number; it is mandatory.
Source
Thrown at src/Polly/Retry/RetryTResultSyntax.cs:59
/// 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>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="onRetry"/> is <see langword="null"/>.</exception>
public static RetryPolicy<TResult> Retry<TResult>(this PolicyBuilder<TResult> policyBuilder, Action<DelegateResult<TResult>, int, Context> onRetry) =>
policyBuilder.Retry(1, onRetry);
/// <summary>View on GitHub (pinned to d0e46bdb1e)
Solutions
- Pass a non-null Action<DelegateResult<TResult>, int>.
- If no callback is wanted, use the Retry(int) overload that omits onRetry.
Example fix
// before
var policy = Policy.HandleResult<int>(r => r < 0).Retry(3, null);
// after
var policy = Policy.HandleResult<int>(r => r < 0).Retry(3, (outcome, attempt) => log.LogWarning("retry {Attempt}", attempt)); Defensive patterns
Strategy: validation
Validate before calling
if (onRetry is null) throw new ArgumentNullException(nameof(onRetry)); var policy = Policy.HandleResult<int>(r => r < 0).Retry(3, onRetry);
Prevention
- Enable nullable reference types.
- If no callback is needed, use the Retry(int) overload that omits onRetry.
- Centralize policy construction in a factory to avoid null callbacks.
When it happens
Trigger: Calling Policy.HandleResult<T>(...).Retry(retryCount, null) with onRetry typed Action<DelegateResult<TResult>, int>.
Common situations: Removed logging; field null; overload-resolution confusion with the Context-bearing variant.
Related errors
- sleepDurations
- Value must be greater than or equal to zero.
- onRetry
- onRetryAsync
- Value must be greater than or equal to zero.
AI-assisted analysis of App-vNext/Polly@d0e46bdb1e (2026-08-13).
Data as JSON: /api/errors/5757f8b6c7c65b94.
Report an issue: GitHub.