dotnet/reactive · error · ArgumentNullException
throw new ArgumentNullException(nameof(observer));
Error message
throw new ArgumentNullException(nameof(observer));
What it means
The Retry operator requires a downstream observer to feed retried source notifications to. System.Reactive.Async throws ArgumentNullException immediately when the observer argument is null, before any subscription work starts, to fail fast instead of crashing later inside Catch/Repeat.
Solutions
- Pass a non-null IAsyncObserver<TSource> as the observer argument, e.g. create one via AsyncObserver.Create or chain from an existing pipeline.
- Check the code that produces the observer — it is returning null; fix the factory/container registration.
- If the observer is optional by design, guard the call site before invoking Retry.
Example fix
// before var (obs, disp) = AsyncObserver.Retry(observer, source); // observer is null // after if (observer == null) observer = AsyncObserver.Create<TSource>(...); var (obs, disp) = AsyncObserver.Retry(observer, source);
Defensive patterns
Strategy: validation
Validate before calling
if (observer == null) throw new InvalidOperationException("observer must be constructed before Retry");
var (obs, disp) = AsyncObserver.Retry(observer, source); Type guard
static bool HasObserver<TSource>(IAsyncObserver<TSource> o) => o is not null;
Try / catch
try { var (obs, disp) = AsyncObserver.Retry(observer, source); }
catch (ArgumentNullException ex) when (ex.ParamName == "observer") { /* fix wiring; use default observer */ } Prevention
- Never store observers in nullable fields; create them inline where Retry is called.
- Make observer factories non-nullable by contract (return throw-if-null).
- Enable C# nullable reference types so null flow is caught at compile time.
When it happens
Trigger: Calling AsyncObserver.Retry<TSource>(null, someSource) — passing a null IAsyncObserver<TSource> as the first argument.
Common situations: Observers produced by a factory method or DI container that returned null; refactoring that removed observer construction but kept the Retry call; conditional observer wiring where a variable is unassigned on some paths.
Related errors
- Value cannot be null. (Parameter 'keySelector')
- Value cannot be null. (Parameter 'durationSelector')
- Value cannot be null. (Parameter 'source')
- throw new ArgumentNullException(nameof(scheduler));
- throw new ArgumentNullException(nameof(observer));
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/22c4773a57071647.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Retry.cs:55
source,
retryCount,
static async (source, retryCount, observer) =>
{
var (sink, inner) = AsyncObserver.Retry(observer, source, retryCount);
var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false);
return StableCompositeAsyncDisposable.Create(subscription, inner);
});
}
}
public partial class AsyncObserver
{
public static (IAsyncObserver<TSource>, IAsyncDisposable) Retry<TSource>(IAsyncObserver<TSource> observer, IAsyncObservable<TSource> source)
{
if (observer == null)
throw new ArgumentNullException(nameof(observer));
if (source == null)
throw new ArgumentNullException(nameof(source));
return Catch(observer, Repeat(source).GetEnumerator());
}
public static (IAsyncObserver<TSource>, IAsyncDisposable) Retry<TSource>(IAsyncObserver<TSource> observer, IAsyncObservable<TSource> source, int retryCount)
{
if (observer == null)
throw new ArgumentNullException(nameof(observer));
if (source == null)
throw new ArgumentNullException(nameof(source));
if (retryCount < 0)
throw new ArgumentOutOfRangeException(nameof(retryCount));
return Catch(observer, Enumerable.Repeat(source, retryCount).GetEnumerator());
}
}View on GitHub (pinned to 94b5d5ab91)