dotnet/reactive · error · ArgumentNullException
rightDurationSelector
Error message
rightDurationSelector
What it means
The Join operator throws ArgumentNullException because the rightDurationSelector delegate was null. This delegate maps each right item to its duration observable and is required for windowed join semantics. The library validates it eagerly at call time.
Solutions
- Supply a non-null Func<TRight, IAsyncObservable<TRightDuration>> as the fourth argument.
- Ensure the delegate variable is initialized before the call.
- Use a stub selector returning an appropriate duration observable when the value is genuinely optional.
Example fix
// before var result = left.Join(right, l => l.Duration, null, (l, r) => (l, r)); // after var result = left.Join(right, l => l.Duration, r => AsyncObservable.Empty<TRightDuration>(), (l, r) => (l, r));
Defensive patterns
Strategy: validation
Validate before calling
if (rightDurationSelector is null) throw new ArgumentException("rightDurationSelector is required", nameof(rightDurationSelector)); Type guard
bool SelectorSet<TR, TD>(Func<TR, IAsyncObservable<TD>>? f) => f is not null;
Try / catch
try { var joined = left.Join(right, lds, rds, rs); }
catch (ArgumentNullException ex) when (ex.ParamName == "rightDurationSelector") { /* supply the missing selector */ } Prevention
- Keep all four Join arguments adjacent in one call; avoid partial construction.
- Check overloads after refactors so no selector argument is dropped.
- Prefer named arguments (rightDurationSelector:) for readability and refactor safety.
When it happens
Trigger: Calling left.Join(right, leftDurationSelector, null, resultSelector) — e.g. the fourth argument was dropped during a refactor or a nullable delegate variable held null.
Common situations: Refactors that changed a Join overload and dropped the right duration selector, or delegates resolved from configuration/DI that default to null.
Related errors
- leftDurationSelector
- resultSelector
- throw new ArgumentNullException(nameof(throttleSelector));
- action (Value cannot be null)
- Argument cannot be null (Parameter name: actionAsync)
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/333bb89d9608d643.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Join.cs:23
using System.Collections.Generic;
using System.Reactive.Disposables;
using System.Threading;
using System.Threading.Tasks;
namespace System.Reactive.Linq
{
public partial class AsyncObservable
{
public static IAsyncObservable<TResult> Join<TLeft, TRight, TLeftDuration, TRightDuration, TResult>(this IAsyncObservable<TLeft> left, IAsyncObservable<TRight> right, Func<TLeft, IAsyncObservable<TLeftDuration>> leftDurationSelector, Func<TRight, IAsyncObservable<TRightDuration>> rightDurationSelector, Func<TLeft, 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 CreateAsyncObservable<TResult>.From(
left,
(right, leftDurationSelector, rightDurationSelector, resultSelector),
static async (left, state, observer) =>
{
var subscriptions = new CompositeAsyncDisposable();
var (leftObserver, rightObserver, disposable) = AsyncObserver.Join(observer, subscriptions, state.leftDurationSelector, state.rightDurationSelector, state.resultSelector);
var leftSubscription = await left.SubscribeSafeAsync(leftObserver).ConfigureAwait(false);
await subscriptions.AddAsync(leftSubscription).ConfigureAwait(false);
var rightSubscription = await state.right.SubscribeSafeAsync(rightObserver).ConfigureAwait(false);
await subscriptions.AddAsync(rightSubscription).ConfigureAwait(false);
View on GitHub (pinned to 94b5d5ab91)