App-vNext/Polly · error · ArgumentNullException
sleepDurationProvider
Error message
sleepDurationProvider
What it means
ArgumentNullException thrown at construction by the 4-argument WaitAndRetry<TResult>(retryCount, Func<int,DelegateResult<TResult>,Context,TimeSpan> sleepDurationProvider, Action<...> onRetry) when sleepDurationProvider is null. The provider is invoked per attempt to compute the wait, so a null value would throw later during execution; Polly validates it eagerly with parameter name 'sleepDurationProvider'.
Source
Thrown at src/Polly/Retry/RetryTResultSyntax.cs:285
/// </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="sleepDurationProvider">The function that provides the duration to wait for a particular retry attempt.</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="sleepDurationProvider"/> or <paramref name="onRetry"/> is <see langword="null"/>.</exception>
public static RetryPolicy<TResult> WaitAndRetry<TResult>(this PolicyBuilder<TResult> policyBuilder, int retryCount, Func<int, TimeSpan> sleepDurationProvider, Action<DelegateResult<TResult>, TimeSpan, int, Context> onRetry)
{
if (retryCount < 0)
{
throw new ArgumentOutOfRangeException(nameof(retryCount), "Value must be greater than or equal to zero.");
}
if (sleepDurationProvider == null)
{
throw new ArgumentNullException(nameof(sleepDurationProvider));
}
if (onRetry == null)
{
throw new ArgumentNullException(nameof(onRetry));
}
var sleepDurations = Enumerable.Range(1, retryCount)
.Select(sleepDurationProvider);
return new RetryPolicy<TResult>(
policyBuilder,
onRetry,
retryCount,
sleepDurationsEnumerable: sleepDurations);
}
/// <summary>View on GitHub (pinned to d0e46bdb1e)
Solutions
- Supply a provider such as n => TimeSpan.FromSeconds(n) or a backoff function.
- Use a simpler WaitAndRetry overload (fixed TimeSpan list) if dynamic durations are not needed.
- Pass an existing provider instance variable confirmed non-null.
Example fix
// before
var p = Policy.HandleResult<int>(r => r == 0).WaitAndRetry(3, null, onRetry);
// after
var p = Policy.HandleResult<int>(r => r == 0)
.WaitAndRetry(3, (attempt, outcome, ctx) => Backoff.Decorate(attempt), onRetry); Defensive patterns
Strategy: validation
Validate before calling
if (sleepDurationProvider == null) throw new InvalidOperationException("sleepDurationProvider required.");
var policy = Policy.HandleResult<T>(pred).WaitAndRetry(retryCount, sleepDurationProvider, onRetry); Type guard
static bool IsProvider<TResult>(Func<int, DelegateResult<TResult>, Context, TimeSpan> p) => p is not null;
Prevention
- Supply a provider (e.g. exponential backoff) or switch to a fixed-sleepDurations overload.
- Enable nullable reference types.
- Register DI providers explicitly and assert non-null at startup.
When it happens
Trigger: Calling policyBuilder.WaitAndRetry<TResult>(retryCount, null, onRetry) where the second argument (the context-aware provider) is null. Also when a Func field wired from config is null.
Common situations: Developer wired onRetry but forgot to supply the duration provider; a DI-registered provider type failed to resolve; refactor changed the provider signature and left a null.
Related errors
- sleepDurations
- Value cannot be null.
- Value cannot be null.
- Value must be greater than 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/000e9f98ba4fc564.
Report an issue: GitHub.