App-vNext/Polly · error · ArgumentNullException
onTimeoutAsync
Error message
onTimeoutAsync
What it means
Thrown by the legacy Polly TimeoutAsync overload that accepts a 3-argument onTimeoutAsync callback (Context, TimeSpan, Task). The method guards its onTimeoutAsync parameter with ArgumentNullException at the very top, before delegating to the 4-argument overload. This is a construction-time validation, not a runtime timeout error — the policy is never created when the timeout callback is null.
Source
Thrown at src/Polly/Timeout/AsyncTimeoutSyntax.cs:360
/// <exception cref="ArgumentNullException">Thrown when <paramref name="onTimeoutAsync"/> is <see langword="null"/>.</exception>
public static AsyncTimeoutPolicy TimeoutAsync(Func<Context, TimeSpan> timeoutProvider, Func<Context, TimeSpan, Task, Exception, Task> onTimeoutAsync) =>
TimeoutAsync(timeoutProvider, TimeoutStrategy.Optimistic, onTimeoutAsync);
/// <summary>
/// Builds an <see cref="AsyncPolicy" /> that will wait asynchronously for a delegate to complete for a specified period of time. A <see cref="TimeoutRejectedException" /> will be thrown if the delegate does not complete within the configured timeout.
/// </summary>
/// <param name="timeoutProvider">A function to provide the timeout for this execution.</param>
/// <param name="timeoutStrategy">The timeout strategy.</param>
/// <param name="onTimeoutAsync">An action to call on timeout, passing the execution context, the timeout applied, and a <see cref="Task" /> capturing the abandoned, timed-out action.
/// <remarks>The Task parameter will be null if the executed action responded cooperatively to cancellation before the policy timed it out.</remarks></param>
/// <returns>The policy instance.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="timeoutProvider"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="onTimeoutAsync"/> is <see langword="null"/>.</exception>
public static AsyncTimeoutPolicy TimeoutAsync(Func<Context, TimeSpan> timeoutProvider, TimeoutStrategy timeoutStrategy, Func<Context, TimeSpan, Task, Task> onTimeoutAsync)
{
if (onTimeoutAsync == null)
{
throw new ArgumentNullException(nameof(onTimeoutAsync));
}
return TimeoutAsync(timeoutProvider, timeoutStrategy, (ctx, timeout, task, _) => onTimeoutAsync(ctx, timeout, task));
}
/// <summary>
/// Builds an <see cref="AsyncPolicy" /> that will wait asynchronously for a delegate to complete for a specified period of time. A <see cref="TimeoutRejectedException" /> will be thrown if the delegate does not complete within the configured timeout.
/// </summary>
/// <param name="timeoutProvider">A function to provide the timeout for this execution.</param>
/// <param name="timeoutStrategy">The timeout strategy.</param>
/// <param name="onTimeoutAsync">An action to call on timeout, passing the execution context, the timeout applied, the <see cref="Task" /> capturing the abandoned, timed-out action, and the captured <see cref="Exception"/>.
/// <remarks>The Task parameter will be null if the executed action responded cooperatively to cancellation before the policy timed it out.</remarks></param>
/// <returns>The policy instance.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="timeoutProvider"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="onTimeoutAsync"/> is <see langword="null"/>.</exception>
public static AsyncTimeoutPolicy TimeoutAsync(
Func<Context, TimeSpan> timeoutProvider,
TimeoutStrategy timeoutStrategy,View on GitHub (pinned to d0e46bdb1e)
Solutions
- Pass a non-null Func<Context, TimeSpan, Task, Task>, e.g. an inline lambda (_, __, ___) => Task.CompletedTask if you have no work to do on timeout.
- If you do not need a timeout callback at all, call the 2-argument overload TimeoutAsync(timeoutProvider, timeoutStrategy) which wires an empty default handler.
- Trace where the null value originates (DI registration, optional parameter, uninitialized field) and fix the assignment at the source.
Example fix
// before Policy.TimeoutAsync(provider, TimeoutStrategy.Optimistic, null); // after Policy.TimeoutAsync(provider, TimeoutStrategy.Optimistic, (ctx, ts, task) => Task.CompletedTask);
Defensive patterns
Strategy: validation
Validate before calling
if (onTimeoutAsync is null) throw new ArgumentException("onTimeoutAsync must be supplied", nameof(onTimeoutAsync));
var policy = Policy.TimeoutAsync(provider, TimeoutStrategy.Optimistic, onTimeoutAsync); Type guard
static bool HasTimeoutHandler(Func<Context, TimeSpan, Task, Task> cb) => cb is not null;
Prevention
- Prefer the overload that omits the callback when you have nothing to do on timeout.
- Treat null callbacks as a configuration error and fail at startup, not at policy construction.
- Use C# 8+ nullable reference types so the compiler rejects passing null.
When it happens
Trigger: Calling Policy.TimeoutAsync(timeoutProvider, timeoutStrategy, null) where the third argument (the Func<Context, TimeSpan, Task, Task> onTimeoutAsync) is null. Also triggered when a variable holding the callback was never assigned or was conditionally set to null.
Common situations: Refactoring code where the onTimeout callback was previously inlined and later extracted into a nullable field; DI containers injecting an unset callback; copy-paste from a simpler overload that omits the callback.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
AI-assisted analysis of App-vNext/Polly@d0e46bdb1e (2026-08-13).
Data as JSON: /api/errors/63af7c4611bf6386.
Report an issue: GitHub.