dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'source')

Error message

Value cannot be null. (Parameter 'source')

What it means

The Buffer(count) extension validates its source IAsyncObservable<TSource> and throws ArgumentNullException('observer' wording notwithstanding, the parameter here is 'source') when null. Buffer groups elements into IList<TSource> batches of the given size, which is impossible without a source. AsyncRx.NET validates all operator inputs at composition time so failures happen where the pipeline is built, not mid-stream.

Solutions

  1. Ensure the expression producing the source is non-null before chaining .Buffer(count); null-check or coalesce to AsyncObservable.Empty<TSource>().
  2. Fix the factory/repository method that returned a null IAsyncObservable so it returns a valid (possibly empty) observable.
  3. Catch ArgumentNullException at the composition site to fail fast with a clearer domain message.

Example fix

// before
var batches = GetObservable()?.Buffer(10); // null source when factory fails
// after
var src = GetObservable() ?? AsyncObservable.Empty<MyItem>();
var batches = src.Buffer(10);
Defensive patterns

Strategy: validation

Validate before calling

if (source is null) source = AsyncObservable.Empty<TSource>();
if (count <= 0) throw new ArgumentException("count must be positive", nameof(count));

Type guard

bool IsSubscribable<T>(IAsyncObservable<T>? s) => s is not null;

Try / catch

try { var batches = src.Buffer(count); }
catch (ArgumentNullException ex) { log.LogError(ex, "Buffer composition failed: {Param}", ex.ParamName); throw; }

Prevention

When it happens

Trigger: Calling source.Buffer(count) where source is null — e.g. a method returning IAsyncObservable<T> that returned null on an error path, an uninitialized field, or a null result from a lookup/conditional factory before chaining .Buffer(n).

Common situations: Conditional observable creation (returning null instead of AsyncObservable.Empty<T>()); refactoring that removed the assignment feeding the variable; optional configuration where the observable is only set in some environments.

Related errors


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

Appendix: source

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

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT License.
// See the LICENSE file in the project root for more information. 

using System.Collections.Generic;
using System.Reactive.Concurrency;
using System.Reactive.Disposables;
using System.Threading;
using System.Threading.Tasks;

namespace System.Reactive.Linq
{
    public partial class AsyncObservable
    {
        public static IAsyncObservable<IList<TSource>> Buffer<TSource>(this IAsyncObservable<TSource> source, int count)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (count <= 0)
                throw new ArgumentNullException(nameof(count));

            return CreateAsyncObservable<IList<TSource>>.From(
                source,
                count,
                static (source, count, observer) => source.SubscribeSafeAsync(AsyncObserver.Buffer(observer, count)));
        }

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

View on GitHub (pinned to 94b5d5ab91)