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
- Pass a valid selector, e.g. () => someClosingObservable
- Default the selector at the call site if it is optional: selector ?? DefaultClosingSelector
- Ensure the delegate is registered/assigned before composition
- 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
- Assign delegate dependencies before pipeline composition
- Provide a default closing selector for optional configuration
- Prefer built-in time/count overloads when no per-buffer closing logic exists
- Verify DI-registered delegates resolve non-null at startup
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
- Value cannot be null. (Parameter 'bufferBoundaries')
- action (Value cannot be null)
- scheduler (Value cannot be null)
- Value cannot be null. (Parameter 'selector')
- subjectSelector
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)