dotnet/reactive · error · ArgumentNullException

source

Error message

source

What it means

AsyncObservable.GroupByUntil (the 2-argument overload) throws ArgumentNullException when the source observable is null. GroupByUntil groups elements by key and closes each group when the duration observable fires; without a source there is nothing to subscribe to. All guards run synchronously at call time, before CreateAsyncObservable is invoked.

Solutions

  1. Ensure the source is created (e.g. via CreateAsyncObservable or another operator) before calling GroupByUntil.
  2. Add a null check on the source earlier in your composition code to get a clearer stack trace.
  3. Guard conditional pipelines so GroupByUntil is only invoked with a valid source.

Example fix

// before
IAsyncObservable<Event> source = null;
var grouped = source.GroupByUntil(e => e.Key, g => g.Take(1));
// after
var source = CreateAsyncObservable<Event>.From(...);
var grouped = source.GroupByUntil(e => e.Key, g => g.Take(1));
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

bool CanGroupByUntil<T,TKey>(IAsyncObservable<T>? s, Func<T,TKey>? k) => s is not null && k is not null;

Try / catch

try { var grouped = source.GroupByUntil(k, d); }
catch (ArgumentNullException ex) { /* ex.ParamName tells which argument was null */ }

Prevention

When it happens

Trigger: Calling source.GroupByUntil(keySelector, durationSelector) where the source variable is null, typically an uninitialized IAsyncObservable<TSource> or the null result of a failed factory chain.

Common situations: Chaining operators where an earlier factory returned null; conditional observable construction skipped in a branch; fields not yet assigned when a subscription path runs early.

Related errors


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

Appendix: source

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

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT License.
// See the LICENSE file in the project root for more information. 

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)

View on GitHub (pinned to 94b5d5ab91)