dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'source')

Error message

Value cannot be null. (Parameter 'source')

What it means

The 2-argument GroupByUntil overload throws ArgumentNullException with the full framework message 'Value cannot be null. (Parameter 'source')' for a null source. Functionally identical to the parameter-name-only variant; the difference is only message formatting (this line is where the throw site is reported).

Solutions

  1. Construct or obtain the source observable before calling GroupByUntil.
  2. Check for null earlier in the pipeline and fail with a descriptive error.
  3. In tests, assert that null sources produce ArgumentNullException if that is the contract.

Example fix

// before
var grouped = maybeSource?.GroupByUntil(k, d); // maybeSource null -> throws
// after
if (maybeSource == null) throw new InvalidOperationException("source not configured");
var grouped = maybeSource.GroupByUntil(k, d);
Defensive patterns

Strategy: validation

Validate before calling

if (source is null) throw new ArgumentNullException(nameof(source));

Type guard

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

Try / catch

try { var grouped = source.GroupByUntil(k, d); }
catch (ArgumentNullException ex) when (ex.ParamName == "source") { /* resolve source before subscribing */ }

Prevention

When it happens

Trigger: Same as the base case: invoking source.GroupByUntil(keySelector, durationSelector) with a null IAsyncObservable<TSource>; the throw site lands on line 23 of GroupByUntil.cs depending on runtime inlining/JIT.

Common situations: Pipeline builders whose earlier stage returned null; unit tests deliberately passing null to check guard behavior; deserialized pipeline definitions where the source reference failed to resolve.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/GroupByUntil.cs:23

using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Reactive.Disposables;
using System.Reactive.Subjects;
using System.Threading;
using System.Threading.Tasks;

namespace System.Reactive.Linq
{
    public partial class AsyncObservable
    {
        public static IAsyncObservable<IGroupedAsyncObservable<TKey, TSource>> GroupByUntil<TSource, TKey, TDuration>(this IAsyncObservable<TSource> source, Func<TSource, TKey> keySelector, Func<IGroupedAsyncObservable<TKey, TSource>, IAsyncObservable<TDuration>> durationSelector)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (keySelector == null)
                throw new ArgumentNullException(nameof(keySelector));
            if (durationSelector == null)
                throw new ArgumentNullException(nameof(durationSelector));

            return CreateAsyncObservable<IGroupedAsyncObservable<TKey, TSource>>.From(
                source,
                (keySelector, durationSelector),
                static (source, state, observer) => GroupByUntilCore<TSource, TKey, TSource, TDuration>(source, observer, (o, d) => AsyncObserver.GroupByUntil(o, d, state.keySelector, state.durationSelector)));
        }

        public static IAsyncObservable<IGroupedAsyncObservable<TKey, TSource>> GroupByUntil<TSource, TKey, TDuration>(this IAsyncObservable<TSource> source, Func<TSource, TKey> keySelector, Func<IGroupedAsyncObservable<TKey, TSource>, IAsyncObservable<TDuration>> durationSelector, IEqualityComparer<TKey> comparer)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (keySelector == null)
                throw new ArgumentNullException(nameof(keySelector));
            if (durationSelector == null)
                throw new ArgumentNullException(nameof(durationSelector));
            if (comparer == null)
                throw new ArgumentNullException(nameof(comparer));

View on GitHub (pinned to 94b5d5ab91)