dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'observer')

Error message

Value cannot be null. (Parameter 'observer')

What it means

System.Reactive.Async's Buffer operator requires a downstream IAsyncObserver<IList<TSource>> to emit buffered lists to. The Buffer(observer, count) overload immediately calls Buffer(observer, count, count), and the target overload validates that observer is not null via ArgumentNullException(nameof(observer)). Passing null means the operator has nowhere to forward notifications, so it fails fast before subscribing anything.

Solutions

  1. Pass a valid IAsyncObserver<IList<TSource>> (or use the fluent extension overloads on the source so the observer is supplied automatically).
  2. Check why the expression producing the observer evaluated to null — fix the upstream factory/step instead of the Buffer call.
  3. Add a null guard or Debug.Assert at the pipeline construction site to fail before entering the operator.

Example fix

// before
IAsyncObserver<IList<int>> sink = GetSink(); // may return null
var buf = Buffer(sink, 3);
// after
IAsyncObserver<IList<int>> sink = GetSink() ?? throw new InvalidOperationException("sink factory returned null");
var buf = Buffer(sink, 3);
Defensive patterns

Strategy: validation

Validate before calling

if (observer is null) throw new ArgumentNullException(nameof(observer));
Buffer(observer, count);

Type guard

static bool IsValidObserver<TSource>(IAsyncObserver<IList<TSource>> o) => o is not null;

Try / catch

try { var buf = Buffer(observer, count); } catch (ArgumentNullException ex) when (ex.ParamName == "observer") { /* supply a valid observer or abort pipeline construction */ }

Prevention

When it happens

Trigger: Calling Buffer<TSource>(null, 5) or Buffer<TSource>(null, 5, 5) — the count/count overloads in AsyncRx.NET/System.Reactive.Async/Linq/Operators/Buffer.cs:224-232 — with a null IAsyncObserver<IList<TSource>> as the first argument.

Common situations: Chaining operators where an earlier composition step returned null (e.g. a factory method silently failed); refactoring custom observable pipelines where the observer variable was never initialized; misusing the extension-style API by hand-rolling pipelines instead of fluent chaining so the observer argument gets forgotten.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Buffer.cs:228

                static async (source, bufferClosingSelector, observer) =>
                {
                    var (sourceObserver, closingDisposable) = await AsyncObserver.Buffer<TSource, TBufferClosing>(observer, bufferClosingSelector).ConfigureAwait(false);

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

                    return StableCompositeAsyncDisposable.Create(sourceSubscription, closingDisposable);
                });
        }
    }

    public partial class AsyncObserver
    {
        public static IAsyncObserver<TSource> Buffer<TSource>(IAsyncObserver<IList<TSource>> observer, int count) => Buffer(observer, count, count);

        public static IAsyncObserver<TSource> Buffer<TSource>(IAsyncObserver<IList<TSource>> observer, int count, int skip)
        {
            if (observer == null)
                throw new ArgumentNullException(nameof(observer));
            if (count <= 0)
                throw new ArgumentNullException(nameof(count));
            if (skip <= 0)
                throw new ArgumentNullException(nameof(skip));

            var queue = new Queue<IList<TSource>>();
            var n = 0;

            void CreateBuffer() => queue.Enqueue(new List<TSource>());

            CreateBuffer();

            return Create<TSource>(
                async x =>
                {
                    foreach (var buffer in queue)
                    {
                        buffer.Add(x);

View on GitHub (pinned to 94b5d5ab91)