dotnet/reactive · error · ArgumentNullException

observer

Error message

observer

What it means

AsyncObserver.Dematerialize throws ArgumentNullException when the downstream IAsyncObserver<TSource> is null. The observer receives the dematerialized notifications, so it is required and validated immediately. This overload is used when writing custom operators, so nulls typically come from hand-rolled subscription plumbing.

Solutions

  1. Pass the actual downstream observer from your operator's subscribe delegate.
  2. Validate your own factory inputs before constructing the Dematerialize observer.
  3. Use the built-in Create(source, observer) operator overload instead of manually wiring observers.

Example fix

// before
return source.SubscribeSafeAsync(AsyncObserver.Dematerialize(observer)); // observer null
// after
if (observer == null) throw new ArgumentNullException(nameof(observer));
return source.SubscribeSafeAsync(AsyncObserver.Dematerialize(observer));
Defensive patterns

Strategy: validation

Validate before calling

if (observer is null) throw new ArgumentNullException(nameof(observer));
var dematerializeObserver = AsyncObserver.Dematerialize(observer);

Type guard

bool HasDownstream<T>(IAsyncObserver<T>? o) => o is not null;

Try / catch

try
{
    var o = AsyncObserver.Dematerialize(observer);
}
catch (ArgumentNullException ex) when (ex.ParamName == "observer")
{
    logger.LogError(ex, "Custom operator passed null observer to Dematerialize");
    throw;
}

Prevention

When it happens

Trigger: Calling AsyncObserver.Dematerialize<TSource>(null) inside a custom operator's subscribe path, or forwarding a null observer variable.

Common situations: Custom Create(...) lambdas where the observer parameter is mistakenly null; composing observers where an earlier stage returned null on a factory failure.

Related errors


AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15). Data as JSON: /api/errors/68a8012607df2940. Report an issue: GitHub.

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Dematerialize.cs:23

namespace System.Reactive.Linq
{
    public partial class AsyncObservable
    {
        public static IAsyncObservable<TSource> Dematerialize<TSource>(this IAsyncObservable<Notification<TSource>> source)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));

            return Create<Notification<TSource>, TSource>(source, static (source, observer) => source.SubscribeSafeAsync(AsyncObserver.Dematerialize(observer)));
        }
    }

    public partial class AsyncObserver
    {
        public static IAsyncObserver<Notification<TSource>> Dematerialize<TSource>(IAsyncObserver<TSource> observer)
        {
            if (observer == null)
                throw new ArgumentNullException(nameof(observer));

            return Create<Notification<TSource>>(
                n => n.AcceptAsync(observer),
                observer.OnErrorAsync,
                observer.OnCompletedAsync
            );
        }
    }
}

View on GitHub (pinned to 94b5d5ab91)