App-vNext/Polly · error · ArgumentNullException
sleepDurationProvider
Error message
sleepDurationProvider
What it means
ArgumentNullException is thrown when sleepDurationProvider is null in WaitAndRetryForeverAsync(Func<int,TimeSpan> sleepDurationProvider, Action<Exception,TimeSpan> onRetry). This function is the sole source of wait durations for the infinite retry policy and cannot be omitted.
Source
Thrown at src/Polly/Retry/AsyncRetrySyntax.cs:886
=> policyBuilder.WaitAndRetryForeverAsync(sleepDurationProvider, EmptyHandlerWithContext);
/// <summary>
/// Builds an <see cref="AsyncRetryPolicy"/> that will wait and retry indefinitely
/// calling <paramref name="onRetry"/> on each retry with the raised exception.
/// On each retry, the duration to wait is calculated by calling <paramref name="sleepDurationProvider" /> with
/// the current retry number (1 for first retry, 2 for second etc).
/// </summary>
/// <param name="policyBuilder">The policy builder.</param>
/// <param name="sleepDurationProvider">A function providing the duration to wait before retrying.</param>
/// <param name="onRetry">The action to call on each retry.</param>
/// <returns>The policy instance.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="sleepDurationProvider"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="onRetry"/> is <see langword="null"/>.</exception>
public static AsyncRetryPolicy WaitAndRetryForeverAsync(this PolicyBuilder policyBuilder, Func<int, TimeSpan> sleepDurationProvider, Action<Exception, TimeSpan> onRetry)
{
if (sleepDurationProvider == null)
{
throw new ArgumentNullException(nameof(sleepDurationProvider));
}
if (onRetry == null)
{
throw new ArgumentNullException(nameof(onRetry));
}
return policyBuilder.WaitAndRetryForeverAsync(
(retryCount, _) => sleepDurationProvider(retryCount),
(exception, timespan, _) => onRetry(exception, timespan));
}
/// <summary>
/// Builds an <see cref="AsyncRetryPolicy"/> that will wait and retry indefinitely
/// calling <paramref name="onRetry"/> on each retry with the raised exception and retry count.
/// On each retry, the duration to wait is calculated by calling <paramref name="sleepDurationProvider" /> with
/// the current retry number (1 for first retry, 2 for second etc).
/// </summary>View on GitHub (pinned to d0e46bdb1e)
Solutions
- Supply a non-null lambda: retryAttempt => TimeSpan.FromSeconds(retryAttempt).
- Verify DI registration of the provider before building the policy.
- Use a named local function instead of a variable to guarantee non-null.
Example fix
// before .WaitAndRetryForeverAsync(null, onRetry) // after .WaitAndRetryForeverAsync(retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), onRetry)
Defensive patterns
Strategy: validation
Validate before calling
if (sleepDurationProvider is null)
throw new InvalidOperationException("sleepDurationProvider must be configured."); Type guard
static bool IsValidProvider(Func<int, TimeSpan> provider) => provider is not null;
Prevention
- Inline the provider lambda at the call site.
- Register provider delegates via DI with non-null factory methods.
When it happens
Trigger: Calling WaitAndRetryForeverAsync with a null sleepDurationProvider — typically from a factory or DI container that did not resolve the delegate.
Common situations: DI registration missing for the provider delegate, or a conditional assignment that left the variable null on an unhandled branch.
Related errors
AI-assisted analysis of App-vNext/Polly@d0e46bdb1e (2026-08-13).
Data as JSON: /api/errors/666d35afce551b65.
Report an issue: GitHub.