dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'bufferBoundaries')
Error message
Value cannot be null. (Parameter 'bufferBoundaries')
What it means
Genuine ArgumentNullException: the boundary overload Buffer(source, bufferBoundaries) requires a non-null boundary observable; it is used to subscribe to buffer-closing signals, so null is rejected up front.
Solutions
- Create a real boundary observable (e.g. from a timer or interval) before calling
- Fall back to AsyncObservable.Never<TBoundary>() when no boundaries are needed
- Guard the call site and use a time/count overload instead when boundaries are absent
- Fix the boundary factory returning null
Example fix
// before var buf = src.Buffer(boundaries); // after var buf = src.Buffer(boundaries ?? AsyncObservable.Never<Unit>());
Defensive patterns
Strategy: type-guard
Validate before calling
if (bufferBoundaries == null) bufferBoundaries = AsyncObservable.Never<TBufferBoundary>();
Type guard
static IAsyncObservable<B> NonNullBoundaries<B>(IAsyncObservable<B> b) => b ?? AsyncObservable.Never<B>();
Try / catch
try { var buf = source.Buffer(bufferBoundaries); }
catch (ArgumentNullException ex) when (ex.ParamName == "bufferBoundaries")
{
// no boundaries available: fall back to time-based buffering
var buf = source.Buffer(TimeSpan.FromSeconds(10), 100);
} Prevention
- Never return null boundary streams; use Never or Empty
- Ensure boundary emitters (timers, events) are started before composition
- Prefer switching to a time/count overload when boundaries are genuinely absent
When it happens
Trigger: Calling Buffer(source, null); a boundaries factory method returning null; conditional logic that only sometimes creates the boundary stream.
Common situations: Boundary stream created from a timer/event emitter that failed to start; null returned from a lookup of an existing stream by key.
Related errors
- Value cannot be null. (Parameter 'bufferClosingSelector')
- scheduler (Value cannot be null)
- action (Value cannot be null)
- Value cannot be null. (Parameter 'disposable')
- Value cannot be null. (Parameter 'disposable')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/be6db688c5caee6e.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Buffer.cs:182
return CreateAsyncObservable<IList<TSource>>.From(
source,
(timeSpan, count, scheduler),
static async (source, state, observer) =>
{
var (sink, timer) = await AsyncObserver.Buffer(observer, state.timeSpan, state.count, state.scheduler).ConfigureAwait(false);
var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false);
return StableCompositeAsyncDisposable.Create(subscription, timer);
});
}
public static IAsyncObservable<IList<TSource>> Buffer<TSource, TBufferBoundary>(this IAsyncObservable<TSource> source, IAsyncObservable<TBufferBoundary> bufferBoundaries)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (bufferBoundaries == null)
throw new ArgumentNullException(nameof(bufferBoundaries));
return CreateAsyncObservable<IList<TSource>>.From(
source,
bufferBoundaries,
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)View on GitHub (pinned to 94b5d5ab91)