dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'bufferClosingSelector')

Error message

Value cannot be null. (Parameter 'bufferClosingSelector')

What it means

Genuine ArgumentNullException: the closing-selector overload Buffer(source, bufferClosingSelector) requires a non-null factory Func<IAsyncObservable<TBufferClosing>> that is called for each buffer to obtain its closing observable; passing null is rejected immediately.

Solutions

  1. Pass a valid selector, e.g. () => someClosingObservable
  2. Default the selector at the call site if it is optional: selector ?? DefaultClosingSelector
  3. Ensure the delegate is registered/assigned before composition
  4. Use a time/count Buffer overload when no closing selector is needed

Example fix

// before
var buf = src.Buffer(bufferClosingSelector);
// after
var buf = src.Buffer(bufferClosingSelector ?? (Func<IAsyncObservable<TBufferClosing>>)(() => AsyncObservable.Never<TBufferClosing>()));
Defensive patterns

Strategy: type-guard

Validate before calling

if (bufferClosingSelector == null) throw new InvalidOperationException("bufferClosingSelector must be provided");

Type guard

static Func<IAsyncObservable<C>> RequireSelector<C>(Func<IAsyncObservable<C>> f) => f ?? (() => AsyncObservable.Never<C>());

Try / catch

try { var buf = source.Buffer(bufferClosingSelector); }
catch (ArgumentNullException ex) when (ex.ParamName == "bufferClosingSelector")
{
    var buf = source.Buffer(TimeSpan.FromSeconds(30), 100);
}

Prevention

When it happens

Trigger: Calling Buffer(source, null); passing a method group whose target is null, or a selector field not yet assigned.

Common situations: Selector supplied via dependency injection or configuration of delegates that was never registered; refactoring removed the selector assignment.

Related errors


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

Appendix: source

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

                static async (source, bufferBoundaries, observer) =>
                {
                    var (sourceObserver, boundariesObserver) = AsyncObserver.Buffer<TSource, TBufferBoundary>(observer);

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

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

        // REVIEW: This overload is inherited from Rx but arguably a bit esoteric as it doesn't provide context to the closing selector.

        public static IAsyncObservable<IList<TSource>> Buffer<TSource, TBufferClosing>(this IAsyncObservable<TSource> source, Func<IAsyncObservable<TBufferClosing>> bufferClosingSelector)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (bufferClosingSelector == null)
                throw new ArgumentNullException(nameof(bufferClosingSelector));

            return CreateAsyncObservable<IList<TSource>>.From(
                source,
                bufferClosingSelector,
                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);

View on GitHub (pinned to 94b5d5ab91)