App-vNext/Polly · error · ArgumentNullException
Value cannot be null.
Error message
Value cannot be null.
What it means
Thrown by AsyncRetrySyntax.RetryAsync(this PolicyBuilder, retryCount, Action<Exception,int> onRetry) when onRetry is null. The callback is invoked on each retry, so a null callback would cause a NullReferenceException at retry time.
Source
Thrown at src/Polly/Retry/AsyncRetrySyntax.cs:64
/// <exception cref="ArgumentNullException">Thrown when <paramref name="onRetryAsync"/> is <see langword="null"/>.</exception>
public static AsyncRetryPolicy RetryAsync(this PolicyBuilder policyBuilder, Func<Exception, int, Task> onRetryAsync) =>
policyBuilder.RetryAsync(1, onRetryAsync: (outcome, i, _) => onRetryAsync(outcome, i));
/// <summary>
/// Builds an <see cref="AsyncRetryPolicy" /> that will retry <paramref name="retryCount" /> times
/// calling <paramref name="onRetry" /> on each retry with the raised exception and retry count.
/// </summary>
/// <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 AsyncRetryPolicy RetryAsync(this PolicyBuilder policyBuilder, int retryCount, Action<Exception, int> onRetry)
{
if (onRetry == null)
{
throw new ArgumentNullException(nameof(onRetry));
}
#pragma warning disable 1998 // async method has no awaits, will run synchronously
return policyBuilder.RetryAsync(retryCount,
onRetryAsync: async (outcome, i, _) => onRetry(outcome, i));
#pragma warning restore 1998
}
/// <summary>
/// Builds an <see cref="AsyncRetryPolicy" /> that will retry <paramref name="retryCount" /> times
/// calling <paramref name="onRetryAsync" /> on each retry with the raised exception and retry count.
/// </summary>
/// <param name="policyBuilder">The policy builder.</param>
/// <param name="retryCount">The retry count.</param>
/// <param name="onRetryAsync">The action to call asynchronously 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="onRetryAsync"/> is <see langword="null"/>.</exception>
public static AsyncRetryPolicy RetryAsync(this PolicyBuilder policyBuilder, int retryCount, Func<Exception, int, Task> onRetryAsync)View on GitHub (pinned to d0e46bdb1e)
Solutions
- Use the no-callback overload: policyBuilder.RetryAsync(retryCount) if you do not need an on-retry action.
- Pass a real Action<Exception, int> (e.g. (ex, i) => logger.LogWarning(ex, "retry {Count}", i)).
- Remove the callback argument entirely if it is unused.
Example fix
// before
var policy = Policy.Handle<HttpRequestException>().RetryAsync(3, onRetry: null);
// after
var policy = Policy.Handle<HttpRequestException>().RetryAsync(3);
// or with a callback:
var policy = Policy.Handle<HttpRequestException>().RetryAsync(3, (ex, i) => logger.LogWarning(ex, "retry {Count}", i)); Defensive patterns
Strategy: validation
Validate before calling
if (onRetry is null) throw new ArgumentException("onRetry callback is required; use the no-callback overload if none is needed.");
var policy = builder.RetryAsync(retryCount, onRetry); Prevention
- Prefer the no-callback overload .RetryAsync(retryCount) when no on-retry action is needed.
- Pass a logging callback by default for observability.
- During refactors, remove the callback argument rather than nulling it.
When it happens
Trigger: Calling .RetryAsync(retryCount, onRetry: null) on a PolicyBuilder when wiring up the legacy async retry with a synchronous on-retry callback.
Common situations: Refactor that removed the logging callback but left the call site; optional callback passed as null where none of the no-callback overloads was chosen.
Related errors
- Value cannot be null.
- onRetryAsync
- onRetry
- Value must be greater than or equal to zero.
- 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/6891db4bf310a8e9.
Report an issue: GitHub.