dotnet/reactive · error · ArgumentNullException
durationSelector
Error message
durationSelector
What it means
This ArgumentNullException is thrown synchronously when the durationSelector argument is null. durationSelector decides how long each group lives (it returns the observable whose completion closes the group), so the operator cannot function without it and rejects null immediately at call time.
Solutions
- Provide a duration selector, e.g. g => g.TakeUntil(timerObservable).
- If group lifetime should be unbounded, use GroupBy instead of passing a null duration selector.
- Null-check any dynamically built selector before invoking GroupByUntil.
Example fix
// before
var grouped = source.GroupByUntil(x => ValueTask.FromResult(x.Id), (Func<IGroupedAsyncObservable<int, T>, IAsyncObservable<Unit>>)null);
// after
var grouped = source.GroupByUntil(
x => ValueTask.FromResult(x.Id),
g => AsyncObservable.Timer(TimeSpan.FromMinutes(5)).Select(_ => Unit.Default)); Defensive patterns
Strategy: validation
Validate before calling
if (durationSelector is null)
{
durationSelector = g => AsyncObservable.Timer(TimeSpan.FromMinutes(5)).Select(_ => Unit.Default);
} Type guard
static bool IsValidSelector<TG, TD>(Func<TG, IAsyncObservable<TD>>? f) => f is not null;
Try / catch
try
{
var grouped = source.GroupByUntil(keySelector, durationSelector);
}
catch (ArgumentNullException ex) when (ex.ParamName == "durationSelector")
{
// build a default duration selector or report misconfiguration
} Prevention
- Use GroupBy when group lifetime should be unbounded instead of passing null.
- Centralize default duration selectors as reusable helper methods.
- Keep long overload calls on one clearly commented line so positional nulls are obvious.
When it happens
Trigger: Calling GroupByUntil with a valid keySelector but null durationSelector, e.g. source.GroupByUntil(keySelector, null) or source.GroupByUntil(keySelector, null, capacity).
Common situations: Overload resolution confusion when adding a capacity/comparer argument shifts positional parameters and the duration lambda slot ends up null; a computed selector variable left uninitialized.
Related errors
- ArgumentNullException: source
- throw new ArgumentNullException(nameof(func));
- Value cannot be null. (Parameter 'elementSelector')
- Value cannot be null. (Parameter 'keySelector')
- Value cannot be null. (Parameter 'durationSelector')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/b12b8ac04501d1b5.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/GroupByUntil.cs:199
if (durationSelector == null)
throw new ArgumentNullException(nameof(durationSelector));
if (comparer == null)
throw new ArgumentNullException(nameof(comparer));
return CreateAsyncObservable<IGroupedAsyncObservable<TKey, TSource>>.From(
source,
(keySelector, durationSelector, comparer),
static (source, state, observer) => GroupByUntilCore<TSource, TKey, TSource, TDuration>(source, observer, (o, d) => AsyncObserver.GroupByUntil(o, d, state.keySelector, state.durationSelector, state.comparer)));
}
public static IAsyncObservable<IGroupedAsyncObservable<TKey, TSource>> GroupByUntil<TSource, TKey, TDuration>(this IAsyncObservable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, Func<IGroupedAsyncObservable<TKey, TSource>, IAsyncObservable<TDuration>> durationSelector, int capacity)
{
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 (capacity < 0)
throw new ArgumentOutOfRangeException(nameof(capacity));
return CreateAsyncObservable<IGroupedAsyncObservable<TKey, TSource>>.From(
source,
(keySelector, durationSelector, capacity),
static (source, state, observer) => GroupByUntilCore<TSource, TKey, TSource, TDuration>(source, observer, (o, d) => AsyncObserver.GroupByUntil(o, d, state.keySelector, state.durationSelector, state.capacity)));
}
public static IAsyncObservable<IGroupedAsyncObservable<TKey, TSource>> GroupByUntil<TSource, TKey, TDuration>(this IAsyncObservable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, Func<IGroupedAsyncObservable<TKey, TSource>, IAsyncObservable<TDuration>> durationSelector, int capacity, 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 (capacity < 0)View on GitHub (pinned to 94b5d5ab91)