dotnet/reactive · error · ArgumentNullException

ArgumentNullException: subscription

Error message

ArgumentNullException: subscription

What it means

Thrown when the subscription IAsyncDisposable is null in the capacity overload of GroupByUntil. The subscription disposable links the grouping operator to the outer subscription lifetime and must be provided. The guard fires synchronously with the parameter name 'subscription'.

Solutions

  1. Forward the subscription disposable from your composition context
  2. Use a no-op stub disposable in tests instead of null
  3. Use the high-level extension overloads which obtain the subscription automatically

Example fix

// before
return GroupByUntil(observer, null, ks, ds, 16);
// after
return GroupByUntil(observer, subscription, ks, ds, 16);
Defensive patterns

Strategy: validation

Validate before calling

if (subscription == null) throw new ArgumentNullException(nameof(subscription));

Type guard

bool HasSubscription(IAsyncDisposable d) => d is not null;

Try / catch

try
{
    var result = await GroupByUntil(observer, subscription, ks, ds, capacity);
}
catch (ArgumentNullException ex) when (ex.ParamName == "subscription")
{
    // wire the subscription disposable
}

Prevention

When it happens

Trigger: Calling GroupByUntil(observer, null, keySelector, durationSelector, capacity) when composing operators manually outside the AsyncObservable.Run pipeline.

Common situations: Custom operator scaffolding that never created the disposable; test rigs constructing core overloads by hand.

Related errors


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

Appendix: source

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

                throw new ArgumentNullException(nameof(observer));
            if (subscription == null)
                throw new ArgumentNullException(nameof(subscription));
            if (keySelector == null)
                throw new ArgumentNullException(nameof(keySelector));
            if (durationSelector == null)
                throw new ArgumentNullException(nameof(durationSelector));
            if (comparer == null)
                throw new ArgumentNullException(nameof(comparer));

            return GroupByUntil(observer, subscription, keySelector, durationSelector, int.MaxValue, comparer);
        }

        public static ValueTask<(IAsyncObserver<TSource>, IAsyncDisposable)> GroupByUntil<TSource, TKey, TDuration>(IAsyncObserver<IGroupedAsyncObservable<TKey, TSource>> observer, IAsyncDisposable subscription, Func<TSource, TKey> keySelector, Func<IGroupedAsyncObservable<TKey, TSource>, IAsyncObservable<TDuration>> durationSelector, int capacity)
        {
            if (observer == null)
                throw new ArgumentNullException(nameof(observer));
            if (subscription == null)
                throw new ArgumentNullException(nameof(subscription));
            if (keySelector == null)
                throw new ArgumentNullException(nameof(keySelector));
            if (durationSelector == null)
                throw new ArgumentNullException(nameof(durationSelector));
            if (capacity < 0)
                throw new ArgumentOutOfRangeException(nameof(capacity));

            return GroupByUntil(observer, subscription, keySelector, durationSelector, capacity, EqualityComparer<TKey>.Default);
        }

        public static ValueTask<(IAsyncObserver<TSource>, IAsyncDisposable)> GroupByUntil<TSource, TKey, TDuration>(IAsyncObserver<IGroupedAsyncObservable<TKey, TSource>> observer, IAsyncDisposable subscription, Func<TSource, TKey> keySelector, Func<IGroupedAsyncObservable<TKey, TSource>, IAsyncObservable<TDuration>> durationSelector, int capacity, IEqualityComparer<TKey> comparer)
        {
            if (observer == null)
                throw new ArgumentNullException(nameof(observer));
            if (subscription == null)
                throw new ArgumentNullException(nameof(subscription));
            if (keySelector == null)
                throw new ArgumentNullException(nameof(keySelector));

View on GitHub (pinned to 94b5d5ab91)