dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'observer')

Error message

Value cannot be null. (Parameter 'observer')

What it means

ArgumentNullException thrown by the observer-level factory AsyncObserver.LastOrDefault<TSource>(IAsyncObserver<TSource>) when the downstream observer is null. This factory builds the operator's observation logic; it is normally invoked via LastOrDefaultAsync with a valid observer, so hitting it means null was passed directly into the observer factory.

Solutions

  1. Pass a valid IAsyncObserver<T> instance to the factory
  2. Validate the observer in the surrounding custom operator before delegating
  3. Use the public LastOrDefault operator instead of the observer factory directly
  4. Check the observer-producing call upstream for null returns

Example fix

// before
var obs = AsyncObserver.LastOrDefault(downstream);
// after
if (downstream == null) throw new ArgumentNullException(nameof(downstream));
var obs = AsyncObserver.LastOrDefault(downstream);
Defensive patterns

Strategy: validation

Validate before calling

if (observer is null) throw new ArgumentNullException(nameof(observer));

Type guard

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

Try / catch

try
{
    var obs = AsyncObserver.LastOrDefault(downstream);
}
catch (ArgumentNullException ex) when (ex.ParamName == "observer")
{
    // downstream observer was not wired; fix composition
}

Prevention

When it happens

Trigger: Calling AsyncObserver.LastOrDefault<T>(null), or building a custom subscription pipeline that forwards a null downstream observer.

Common situations: Custom operator implementations whose observer parameter was not validated upstream, test harnesses constructing observers manually, or composition order mistakes.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/LastOrDefault.cs:57

        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (predicate == null)
                throw new ArgumentNullException(nameof(predicate));

            return CreateAsyncObservable<TSource>.From(
                source,
                predicate,
                static (source, predicate, observer) => source.SubscribeSafeAsync(AsyncObserver.LastOrDefault(observer, predicate)));
        }
    }

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

            var hasValue = false;
            var lastValue = default(TSource);

            return Create<TSource>(
                x =>
                {
                    hasValue = true;
                    lastValue = x;

                    return default;
                },
                observer.OnErrorAsync,
                async () =>
                {
                    await observer.OnNextAsync(hasValue ? lastValue : default).ConfigureAwait(false);
                    await observer.OnCompletedAsync().ConfigureAwait(false);
                }

View on GitHub (pinned to 94b5d5ab91)