dotnet/reactive · error · ArgumentNullException
resultSelector
Error message
resultSelector
What it means
GroupJoin validates every delegate argument before doing any work and throws ArgumentNullException when the resultSelector delegate is null. The resultSelector combines each left value with the matching right observable into the final result, so the operator cannot proceed without it. This fail-fast guard surfaces the programming mistake at the call site instead of failing later inside the subscription.
Solutions
- Pass a non-null resultSelector delegate that maps (TLeft, IAsyncObservable<TRight>) to TResult.
- Check argument order — ensure the lambda lands in the fifth parameter position, not shifted by a missing duration selector.
- If the selector is conditionally supplied, default it to a valid fallback function before calling GroupJoin.
Example fix
// before var joined = AsyncObservable.GroupJoin(left, right, ld, rd, (Func<Left, IObservable<Right>, Result>)null); // after var joined = AsyncObservable.GroupJoin(left, right, ld, rd, (l, rObs) => new Result(l, rObs));
Defensive patterns
Strategy: validation
Validate before calling
if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); // or coerce: resultSelector ??= (l, rObs) => Result.Default(l, rObs);
Type guard
bool HasResultSelector(Func<L, IAsyncObservable<R>, T> f) => f is not null;
Try / catch
try { var joined = AsyncObservable.GroupJoin(left, right, ld, rd, resultSelector); }
catch (ArgumentNullException ex) when (ex.ParamName == "resultSelector") { /* supply default selector and retry */ } Prevention
- Never assign delegates to nullable Func fields without a default
- Verify positional argument order when calling 5-parameter operators
- Let the compiler infer lambdas inline rather than declaring typed Func variables initialized to null
When it happens
Trigger: Calling AsyncObservable.GroupJoin(left, right, leftDurationSelector, rightDurationSelector, resultSelector) with a null fifth argument, e.g. passing an uninitialized Func<TLeft, IAsyncObservable<TRight>, TResult> or a misordered argument list that shifts null into the resultSelector position.
Common situations: Builders that assemble operator arguments from nullable configuration or DI-resolved delegates; refactors that changed the selector signature leaving a stale null lambda; conditional logic that assigns the selector only in some branches.
Related errors
- Argument cannot be null (Parameter name: actionAsync)
- scheduler
- new ArgumentNullException(nameof(condition))
- condition
- thenSource
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/4a9a8b17fcef3dc4.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/GroupJoin.cs:26
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)