dotnet/reactive · error · ArgumentNullException
throw new ArgumentNullException(nameof(observer));
Error message
throw new ArgumentNullException(nameof(observer));
What it means
AsyncObserver.Scan<TSource>(observer, func) — the internal observer factory used by the unseeded sync Scan operator — throws ArgumentNullException because the downstream observer was null. This guard protects the observer-wrapping layer; in typical use the public Scan method always supplies a real observer, so hitting this means Scan was invoked through internal APIs with a broken observer.
Solutions
- Pass the actual downstream observer: AsyncObserver.Scan(downstream, func).
- Fix the custom subscription path so the observer is created before Scan is called.
- Prefer the public source.Scan(func) API, which wires the observer for you.
Example fix
// before IAsyncObserver<int> downstream = null; var obs = AsyncObserver.Scan(downstream, (a, b) => a + b); // throws // after var obs = AsyncObserver.Scan(observer, (a, b) => a + b); // observer from the subscription callback
Defensive patterns
Strategy: validation
Validate before calling
if (observer is null) throw new InvalidOperationException("downstream observer must be provided to AsyncObserver.Scan");
var obs = AsyncObserver.Scan(observer, func); Type guard
static bool HasObserver<TSource>(IAsyncObserver<TSource>? o) => o is not null;
Try / catch
try { var obs = AsyncObserver.Scan(observer, f); }
catch (ArgumentNullException ex) when (ex.ParamName == "observer") { log.LogError("observer chain broken"); throw; } Prevention
- Prefer the public source.Scan(func) operator over manual AsyncObserver wiring.
- In custom operators, construct the observer before calling factory methods.
- Keep observer fields non-nullable in subscription implementations.
When it happens
Trigger: Calling AsyncObserver.Scan(null, func) directly or via a custom operator that forwards a null IAsyncObserver<TSource> — e.g. a hand-rolled SubscribeSafeAsync path that drops the observer on error.
Common situations: Custom operator/observer implementations reusing AsyncObserver.Scan with an observer that was never constructed; testing internal APIs; observer lost through a nullable pipeline field.
Related errors
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/c42cfc5a44ab129c.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Scan.cs:69
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (func == null)
throw new ArgumentNullException(nameof(func));
return CreateAsyncObservable<TResult>.From(
source,
(func, seed),
static (source, state, observer) => source.SubscribeSafeAsync(AsyncObserver.Scan(observer, state.seed, state.func)));
}
}
public partial class AsyncObserver
{
public static IAsyncObserver<TSource> Scan<TSource>(IAsyncObserver<TSource> observer, Func<TSource, TSource, TSource> func)
{
if (observer == null)
throw new ArgumentNullException(nameof(observer));
if (func == null)
throw new ArgumentNullException(nameof(func));
var hasValue = false;
var value = default(TSource);
return Create<TSource>(
async x =>
{
if (hasValue)
{
try
{
value = func(value, x);
}
catch (Exception ex)
{
await observer.OnErrorAsync(ex).ConfigureAwait(false);View on GitHub (pinned to 94b5d5ab91)