dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'bufferOpenings')

Error message

Value cannot be null. (Parameter 'bufferOpenings')

What it means

The Buffer(source, bufferOpenings, bufferClosingSelector) overload requires a non-null bufferOpenings observable that signals when each buffer starts. Passing null for bufferOpenings throws ArgumentNullException at call time. The library validates arguments eagerly so the failure surfaces at the call site, not inside the subscription.

Solutions

  1. Initialize or fix the bufferOpenings observable so it is non-null before calling Buffer.
  2. Substitute Observable.Empty<TBufferOpening>() when there are genuinely no openings (yields no buffers).
  3. Guard the call: only invoke Buffer when both source and openings streams are available.

Example fix

// before
var buffers = source.Buffer(maybeOpenings, x => closings); // throws if maybeOpenings is null
// after
var openings = maybeOpenings ?? Observable.Empty<Opening>();
var buffers = source.Buffer(openings, x => closings);
Defensive patterns

Strategy: validation

Validate before calling

ArgumentNullException.ThrowIfNull(openings);
var openings = maybeOpenings ?? Observable.Empty<TBufferOpening>();

Type guard

bool HasOpenings<TBufferOpening>(IObservable<TBufferOpening>? openings) => openings is not null;

Try / catch

try { var buffers = source.Buffer(openings, closingSelector); }
catch (ArgumentNullException ex) when (ex.ParamName == "bufferOpenings") { /* supply Observable.Empty<TBufferOpening>() */ }

Prevention

When it happens

Trigger: Calling source.Buffer(openings, selector) where the openings IObservable<TBufferOpening> is null — e.g. an event stream that was never wired up, a Subject that failed to initialize, or a null result from a lookup of opening events.

Common situations: Dynamic UI/event wiring where the opening-signal stream is conditionally created; a service returning null instead of Observable.Empty for the opening stream; copy-pasted operator calls where the openings argument was accidentally dropped or left as an uninitialized variable.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.Multiple.cs:124

        /// </summary>
        /// <typeparam name="TSource">The type of the elements in the source sequence, and in the lists in the result sequence.</typeparam>
        /// <typeparam name="TBufferOpening">The type of the elements in the sequence indicating buffer opening events, also passed to the closing selector to obtain a sequence of buffer closing events.</typeparam>
        /// <typeparam name="TBufferClosing">The type of the elements in the sequences indicating buffer closing events.</typeparam>
        /// <param name="source">Source sequence to produce buffers over.</param>
        /// <param name="bufferOpenings">Observable sequence whose elements denote the creation of new buffers.</param>
        /// <param name="bufferClosingSelector">A function invoked to define the closing of each produced buffer.</param>
        /// <returns>An observable sequence of buffers.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="bufferOpenings"/> or <paramref name="bufferClosingSelector"/> is null.</exception>
        public static IObservable<IList<TSource>> Buffer<TSource, TBufferOpening, TBufferClosing>(this IObservable<TSource> source, IObservable<TBufferOpening> bufferOpenings, Func<TBufferOpening, IObservable<TBufferClosing>> bufferClosingSelector)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            if (bufferOpenings == null)
            {
                throw new ArgumentNullException(nameof(bufferOpenings));
            }

            if (bufferClosingSelector == null)
            {
                throw new ArgumentNullException(nameof(bufferClosingSelector));
            }

            return s_impl.Buffer(source, bufferOpenings, bufferClosingSelector);
        }

        /// <summary>
        /// Projects each element of an observable sequence into consecutive non-overlapping buffers.
        /// </summary>
        /// <typeparam name="TSource">The type of the elements in the source sequence, and in the lists in the result sequence.</typeparam>
        /// <typeparam name="TBufferBoundary">The type of the elements in the sequences indicating buffer boundary events.</typeparam>
        /// <param name="source">Source sequence to produce buffers over.</param>
        /// <param name="bufferBoundaries">Sequence of buffer boundary markers. The current buffer is closed and a new buffer is opened upon receiving a boundary marker.</param>
        /// <returns>An observable sequence of buffers.</returns>

View on GitHub (pinned to 94b5d5ab91)