dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'source')

Error message

Value cannot be null. (Parameter 'source')

What it means

The time-based Buffer(source, timeSpan) operator in Observable.Time.cs validates the source observable first and throws ArgumentNullException when it is null. Time-based operators additionally need the source to schedule buffer windows, so a null source is rejected immediately before any scheduling setup.

Solutions

  1. Ensure the upstream producer returns Observable.Empty<T>() or a valid observable instead of null.
  2. Coalesce before buffering: `(source ?? Observable.Empty<T>()).Buffer(timeSpan)`.
  3. Validate inputs at service construction so the null is caught long before the Rx chain runs.

Example fix

// before
var windows = telemetry.Buffer(TimeSpan.FromSeconds(5)); // telemetry == null

// after
var windows = (telemetry ?? Observable.Empty<Metric>()).Buffer(TimeSpan.FromSeconds(5));
Defensive patterns

Strategy: validation

Validate before calling

if (source is null) source = Observable.Empty<TSource>(); // before time-based Buffer
if (timeSpan < TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(timeSpan));

Type guard

bool HasSource<T>(IObservable<T>? s) => s is not null;

Try / catch

try { var r = src.Buffer(timeSpan); }
catch (ArgumentNullException ex) when (ex.ParamName == "source") { /* use Observable.Empty<T>() */ }

Prevention

When it happens

Trigger: Calling source.Buffer(TimeSpan.FromSeconds(1)) where source is null — e.g. a null-returning producer, an unset event-to-observable conversion result, or a DI dependency not registered.

Common situations: Event streams built from Observable.FromEventPattern where the backing hookup returned null; timers/telemetry streams that are conditionally created; null scheduler/source fields in services composing time-windowed pipelines.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.Time.cs:34

        /// <summary>
        /// Projects each element of an observable sequence into consecutive non-overlapping buffers which are produced based on timing information.
        /// </summary>
        /// <typeparam name="TSource">The type of the elements in the source sequence, and in the lists in the result sequence.</typeparam>
        /// <param name="source">Source sequence to produce buffers over.</param>
        /// <param name="timeSpan">Length of each buffer.</param>
        /// <returns>An observable sequence of buffers.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="timeSpan"/> is less than TimeSpan.Zero.</exception>
        /// <remarks>
        /// Specifying a TimeSpan.Zero value for <paramref name="timeSpan"/> is not recommended but supported, causing the scheduler to create buffers as fast as it can.
        /// Because all source sequence elements end up in one of the buffers, some buffers won't have a zero time span. This is a side-effect of the asynchrony introduced
        /// by the scheduler, where the action to close the current buffer and to create a new buffer may not execute immediately, despite the TimeSpan.Zero due time.
        /// </remarks>
        public static IObservable<IList<TSource>> Buffer<TSource>(this IObservable<TSource> source, TimeSpan timeSpan)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            if (timeSpan < TimeSpan.Zero)
            {
                throw new ArgumentOutOfRangeException(nameof(timeSpan));
            }

            return s_impl.Buffer(source, timeSpan);
        }

        /// <summary>
        /// Projects each element of an observable sequence into consecutive non-overlapping buffers which are produced based on timing information, using the specified scheduler to run timers.
        /// </summary>
        /// <typeparam name="TSource">The type of the elements in the source sequence, and in the lists in the result sequence.</typeparam>
        /// <param name="source">Source sequence to produce buffers over.</param>
        /// <param name="timeSpan">Length of each buffer.</param>
        /// <param name="scheduler">Scheduler to run buffering timers on.</param>
        /// <returns>An observable sequence of buffers.</returns>

View on GitHub (pinned to 94b5d5ab91)