dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'observer')

Error message

Value cannot be null. (Parameter 'observer')

What it means

The observer-based Take(observer, count) factory requires a non-null IAsyncObserver. Passing null makes the resulting operator unable to forward notifications, so the guard at Take.cs:94 throws ArgumentNullException immediately.

Solutions

  1. Pass a valid IAsyncObserver instance (e.g. one created via AsyncObserver.Create).
  2. Check the expression producing the observer; fix whatever returns null upstream.
  3. Verify argument order — count and observer are easily swapped in handwritten calls.
  4. Null-check or assert the observer before calling Take in custom pipeline builders.

Example fix

// before: AsyncObserver.Take(null, 3)  // after: var inner = AsyncObserver.Create<int>(...); AsyncObserver.Take(inner, 3)
Defensive patterns

Strategy: validation

Validate before calling

if (observer == null) throw new ArgumentNullException(nameof(observer)); if (count <= 0) throw new ArgumentOutOfRangeException(nameof(count)); var obs = AsyncObserver.Take(observer, count);

Type guard

static bool CanTake<TSource>(IAsyncObserver<TSource> obs, int count) => obs != null && count > 0;

Try / catch

try { var obs = AsyncObserver.Take(observer, count); } catch (ArgumentNullException ex) when (ex.ParamName == "observer") { /* observer chain was not initialized; abort or substitute */ }

Prevention

When it happens

Trigger: Calling AsyncObserver.Take(null, count); passing the result of a failed composition chain (a method that returned null) into Take.

Common situations: Building custom async observer pipelines manually; intermediate factory returning null after a refactor; misordered arguments so that null lands in the observer slot.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Take.cs:94

                source,
                (duration, scheduler),
                static async (source, state, observer) =>
                {
                    var (sourceObserver, timer) = await AsyncObserver.Take(observer, state.duration).ConfigureAwait(false);

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

                    return StableCompositeAsyncDisposable.Create(subscription, timer);
                });
        }
    }

    public partial class AsyncObserver
    {
        public static IAsyncObserver<TSource> Take<TSource>(IAsyncObserver<TSource> observer, int count)
        {
            if (observer == null)
                throw new ArgumentNullException(nameof(observer));
            if (count <= 0)
                throw new ArgumentOutOfRangeException(nameof(count));

            return Create<TSource>(
                async x =>
                {
                    var remaining = --count;

                    await observer.OnNextAsync(x).ConfigureAwait(false);

                    if (remaining == 0)
                    {
                        await observer.OnCompletedAsync().ConfigureAwait(false);
                    }
                },
                observer.OnErrorAsync,
                observer.OnCompletedAsync
            );

View on GitHub (pinned to 94b5d5ab91)