dotnet/reactive · error · ArgumentNullException

null (Parameter 'observer')

Error message

null (Parameter 'observer')

What it means

AsyncObserver.Append creates an observer that, on completion of the source, emits one extra fixed value. It requires a non-null downstream observer, so a null observer throws ArgumentNullException (message shown as "null (Parameter 'observer')"). The guard runs before the internal Create call wires OnNextAsync/OnErrorAsync/onCompleted delegates.

Solutions

  1. Pass a constructed IAsyncObserver<TSource> as the first argument.
  2. Build the downstream observer before composing Append.
  3. Add a caller-side null assertion with a descriptive message before the call.

Example fix

// before
var obs = AsyncObserver.Append(sinkOpt, 42);
// after
var obs = AsyncObserver.Append(sinkOpt ?? throw new InvalidOperationException("sink missing"), 42);
Defensive patterns

Strategy: validation

Validate before calling

if (observer == null) throw new InvalidOperationException("observer required before AsyncObserver.Append");
var obs = AsyncObserver.Append(observer, value);

Type guard

bool HasObserver<TSource>(IAsyncObserver<TSource>? o) => o is not null;

Try / catch

try { var obs = AsyncObserver.Append(observer, value); }
catch (ArgumentNullException ex) when (ex.ParamName == "observer") { /* construct observer first */ }

Prevention

When it happens

Trigger: Calling AsyncObserver.Append<TSource>(null, value), typically in hand-built observer pipelines or tests that inject the observer later.

Common situations: Custom operator composition where the downstream observer is created lazily and is still null, or a factory method returning null that is passed straight into Append.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Append.cs:138

                    var (sink, disposable) = AsyncObserver.Append(observer, state.scheduler, state.values);

                    await d.AddAsync(disposable).ConfigureAwait(false);

                    var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false);

                    await d.AddAsync(subscription).ConfigureAwait(false);

                    return d;
                });
        }
    }

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

            return Create<TSource>(
                observer.OnNextAsync,
                observer.OnErrorAsync,
                async () =>
                {
                    await observer.OnNextAsync(value).ConfigureAwait(false);
                    await observer.OnCompletedAsync().ConfigureAwait(false);
                }
            );
        }

        public static (IAsyncObserver<TSource>, IAsyncDisposable) Append<TSource>(IAsyncObserver<TSource> observer, TSource value, IAsyncScheduler scheduler)
        {
            if (observer == null)
                throw new ArgumentNullException(nameof(observer));
            if (scheduler == null)
                throw new ArgumentNullException(nameof(scheduler));

View on GitHub (pinned to 94b5d5ab91)