dotnet/reactive · error · ArgumentNullException
leftDurationSelector
Error message
leftDurationSelector
What it means
GroupJoin needs leftDurationSelector to compute, for each left item, the observable whose completion ends that item's join window. A null selector makes windowing impossible, so ArgumentNullException is thrown at call time (third guard in the method).
Solutions
- Provide a duration observable per left item, e.g. `l => timer` or `l => AsyncObservable.Empty<TLeftDuration>()` for windows that end on the next right event per your design.
- If you don't need windowed semantics, use a different operator (e.g. Zip or CombineLatest).
- Check that your lambda actually binds to leftDurationSelector (first selector slot).
Example fix
// before var result = left.GroupJoin(right, null, r => r.Take(1), (l, rs) => rs); // after var result = left.GroupJoin(right, l => leftTimer, r => r.Take(1), (l, rs) => rs);
Defensive patterns
Strategy: validation
Validate before calling
if (leftDurationSelector is null) throw new ArgumentNullException(nameof(leftDurationSelector));
Type guard
bool IsValidSelector<TLeft,TDur>(Func<TLeft, IAsyncObservable<TDur>>? f) => f is not null;
Try / catch
try
{
var result = left.GroupJoin(right, lds, rds, rs);
}
catch (ArgumentNullException ex) when (ex.ParamName == "leftDurationSelector")
{
// fall back to a non-windowed operator (Zip/CombineLatest)
} Prevention
- Always pair GroupJoin with explicit duration observables for both sides.
- Remember parameter order: leftDurationSelector comes before rightDurationSelector.
- If you have no duration semantics, GroupJoin is the wrong operator.
When it happens
Trigger: Calling GroupJoin with null as the `leftDurationSelector` (Func<TLeft, IAsyncObservable<TLeftDuration>>), e.g. `left.GroupJoin(right, null, rds, rs)`.
Common situations: Migrating from Join/SelectMany-style code that lacked duration semantics; overloads confused after adding duration selectors in a refactor; dynamic query builders that skip optional delegates.
Related errors
- rightDurationSelector
- Value cannot be null. (Parameter 'left')
- Value cannot be null. (Parameter 'right')
- Argument cannot be null (Parameter name: functionAsync)
- Argument cannot be null (Parameter name: observer)
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/54417c62223d8e70.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/GroupJoin.cs:22
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<TResult> GroupJoin<TLeft, TRight, TLeftDuration, TRightDuration, TResult>(this IAsyncObservable<TLeft> left, IAsyncObservable<TRight> right, Func<TLeft, IAsyncObservable<TLeftDuration>> leftDurationSelector, Func<TRight, IAsyncObservable<TRightDuration>> rightDurationSelector, Func<TLeft, IAsyncObservable<TRight>, TResult> resultSelector)
{
if (left == null)
throw new ArgumentNullException(nameof(left));
if (right == null)
throw new ArgumentNullException(nameof(right));
if (leftDurationSelector == null)
throw new ArgumentNullException(nameof(leftDurationSelector));
if (rightDurationSelector == null)
throw new ArgumentNullException(nameof(rightDurationSelector));
if (resultSelector == null)
throw new ArgumentNullException(nameof(resultSelector));
return Create<TResult>(async observer =>
{
var subscriptions = new CompositeAsyncDisposable();
var (leftObserver, rightObserver, disposable) = AsyncObserver.GroupJoin(observer, subscriptions, leftDurationSelector, rightDurationSelector, resultSelector);
var leftSubscription = await left.SubscribeSafeAsync(leftObserver).ConfigureAwait(false);
await subscriptions.AddAsync(leftSubscription).ConfigureAwait(false);
var rightSubscription = await right.SubscribeSafeAsync(rightObserver).ConfigureAwait(false);
await subscriptions.AddAsync(rightSubscription).ConfigureAwait(false);
return disposable;View on GitHub (pinned to 94b5d5ab91)