dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'leftDurationSelector')
Error message
Value cannot be null. (Parameter 'leftDurationSelector')
What it means
GroupJoin threw ArgumentNullException because the leftDurationSelector delegate was null. The selector maps each left element to the observable defining its duration window; the public operator validates it synchronously.
Solutions
- Supply a non-null duration selector, e.g. _ => Observable.Timer(TimeSpan.FromSeconds(5)) or _ => Observable.Empty<Unit>() for zero-duration.
- Null-check the delegate before the call and fail with context.
- Use Observable.Never<Unit>() if left elements should stay open indefinitely.
Example fix
// before var joined = left.GroupJoin(right, null, r => r.Window(), (l, rs) => ...); // after var joined = left.GroupJoin(right, _ => Observable.Timer(TimeSpan.FromSeconds(5)), r => r.Window(), (l, rs) => ...);
Defensive patterns
Strategy: validation
Validate before calling
if (leftDurationSelector == null)
leftDurationSelector = _ => Observable.Never<Unit>(); Type guard
bool HasLeftDuration<TLeft>(Func<TLeft, IObservable<Unit>>? f) => f is not null;
Try / catch
try
{
var joined = left.GroupJoin(right, leftDurationSelector, rightDurationSelector, resultSelector);
}
catch (ArgumentNullException ex) when (ex.ParamName == "leftDurationSelector")
{
// use default window policy
} Prevention
- Define a default left-window policy constant in your query-building layer.
- Use Observable.Never<Unit>() or Observable.Empty<Unit>() instead of null to express window semantics.
- Keep duration selectors as required parameters so the compiler catches omissions.
When it happens
Trigger: Calling left.GroupJoin(right, null, rightDurationSelector, resultSelector) — e.g. a window selector built conditionally that ended up null.
Common situations: Conditional window construction; forwarding optional method parameters; forgetting to replace a placeholder null after refactoring the join call.
Related errors
- Value cannot be null. (Parameter 'left')
- Value cannot be null. (Parameter 'resultSelector')
- Value cannot be null. (Parameter 'right')
- Value cannot be null. (Parameter 'rightDurationSelector')
- Value cannot be null. (Parameter 'onCompleted')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/c4efd42255cd2f21.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.StandardSequenceOperators.cs:856
/// <param name="rightDurationSelector">A function to select the duration of each element of the right observable sequence, used to determine overlap.</param>
/// <param name="resultSelector">A function invoked to compute a result element for any element of the left sequence with overlapping elements from the right observable sequence.</param>
/// <returns>An observable sequence that contains result elements computed from source elements that have an overlapping duration.</returns>
/// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> or <paramref name="leftDurationSelector"/> or <paramref name="rightDurationSelector"/> or <paramref name="resultSelector"/> is null.</exception>
public static IObservable<TResult> GroupJoin<TLeft, TRight, TLeftDuration, TRightDuration, TResult>(this IObservable<TLeft> left, IObservable<TRight> right, Func<TLeft, IObservable<TLeftDuration>> leftDurationSelector, Func<TRight, IObservable<TRightDuration>> rightDurationSelector, Func<TLeft, IObservable<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 s_impl.GroupJoin(left, right, leftDurationSelector, rightDurationSelector, resultSelector);
}
#endregion
#region + Join +View on GitHub (pinned to 94b5d5ab91)