dotnet/reactive · error · ArgumentNullException
observer
Error message
observer
What it means
The observer-side Delay extension throws ArgumentNullException because the downstream IAsyncObserver<TSource> is null. Observer operators compose onto an existing observer, and a null observer has nothing to forward delayed notifications to, so the argument is validated immediately. Note this overload already defaults the scheduler, so only the observer itself is at fault here.
Solutions
- Pass a real IAsyncObserver<TSource> — typically the observer handed to your SubscribeAsync lambda.
- If you wrap observers in a chain, verify the innermost observer is constructed before the Delay call.
- Check that any factory producing the observer is not returning null.
Example fix
// before
await AsyncObserver.Delay(observer, TimeSpan.FromSeconds(1)); // observer null here
// after
if (observer == null) throw new InvalidOperationException("observer not yet created");
await AsyncObserver.Delay(observer, TimeSpan.FromSeconds(1)); Defensive patterns
Strategy: validation
Validate before calling
if (observer is null) throw new InvalidOperationException("downstream observer not created before Delay");
var (delayed, disp) = await AsyncObserver.Delay(observer, dueTime); Type guard
static bool CanDelay<TSource>(IAsyncObserver<TSource>? o) => o is not null;
Try / catch
try { var r = await AsyncObserver.Delay(observer, due); }
catch (ArgumentNullException ex) when (ex.ParamName == "observer") { /* log and rethrow with pipeline context */ throw; } Prevention
- In custom operators, apply observer extensions only after the observer parameter is known non-null.
- Never let observer-factory helpers return null.
- Use nullable annotations to catch null observers at compile time.
When it happens
Trigger: Calling AsyncObserver.Delay<TSource>(null, dueTime) — e.g. inside a custom SubscribeAsync where the 'observer' parameter or a captured observer variable is null.
Common situations: Writing a custom operator whose Create callback receives an observer that was never assigned; tests passing null observers; refactors that removed observer construction upstream.
Related errors
- Value cannot be null. (Parameter 'onErrorAsync')
- Value cannot be null. (Parameter 'onCompletedAsync')
- Value cannot be null. (Parameter 'error')
- source
- scheduler
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/fc1e7d5f1c73e305.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Delay.cs:61
source,
(dueTime, scheduler),
static async (source, state, observer) =>
{
var (sink, drain) = await AsyncObserver.Delay(observer, state.dueTime, state.scheduler).ConfigureAwait(false);
var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false);
return StableCompositeAsyncDisposable.Create(subscription, drain);
});
}
}
public partial class AsyncObserver
{
public static Task<(IAsyncObserver<TSource>, IAsyncDisposable)> Delay<TSource>(this IAsyncObserver<TSource> observer, TimeSpan dueTime)
{
if (observer == null)
throw new ArgumentNullException(nameof(observer));
return Delay(observer, dueTime, TaskPoolAsyncScheduler.Default);
}
public static async Task<(IAsyncObserver<TSource>, IAsyncDisposable)> Delay<TSource>(this IAsyncObserver<TSource> observer, TimeSpan dueTime, IAsyncScheduler scheduler)
{
if (observer == null)
throw new ArgumentNullException(nameof(observer));
if (scheduler == null)
throw new ArgumentNullException(nameof(scheduler));
// TODO: Use stopwatch functionality.
var start = scheduler.Now;
var semaphore = new SemaphoreSlim(0);
var gate = new AsyncGate();View on GitHub (pinned to 94b5d5ab91)