dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'right')

Error message

Value cannot be null. (Parameter 'right')

What it means

ArgumentNullException guard in Observable.GroupJoin: the 'right' observable sequence to join against the left sequence was null. Windowed joins require both duration-bearing sequences, so the null right argument is rejected at query construction time.

Solutions

  1. Ensure the right observable is created/registered before the join.
  2. Substitute Observable.Empty<TRight>() when no right source exists.
  3. Null-check before the call and surface a message naming the missing stream.

Example fix

// before
var joined = left.GroupJoin(_rightStream, ...); // _rightStream not yet set
// after
var right = _rightStream ?? Observable.Empty<Right>();
var joined = left.GroupJoin(right, ...);
Defensive patterns

Strategy: validation

Validate before calling

if (right == null)
    throw new InvalidOperationException("Right observable for GroupJoin was not registered.");

Type guard

bool HasRight<T>(IObservable<T>? s) => s is not null;

Try / catch

try
{
    var joined = left.GroupJoin(right, ld, rd, rs);
}
catch (ArgumentNullException ex) when (ex.ParamName == "right")
{
    // register or fall back to Observable.Empty<TRight>()
}

Prevention

When it happens

Trigger: Calling left.GroupJoin(null, leftDurationSelector, rightDurationSelector, resultSelector) — usually a right stream resolved from a nullable source or a failed lookup.

Common situations: Inner stream coming from a cache/registry that returned null; optional inner streams modeled as null; DI wiring where the right stream registration was missing.

Related errors


AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15). Data as JSON: /api/errors/f1699f2608fa1cb4. Report an issue: GitHub.

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.StandardSequenceOperators.cs:851

        /// <typeparam name="TRightDuration">The type of the elements in the duration sequence denoting the computed duration of each element in the right source sequence.</typeparam>
        /// <typeparam name="TResult">The type of the elements in the result sequence, obtained by invoking the result selector function for source elements with overlapping duration.</typeparam>
        /// <param name="left">The left observable sequence to join elements for.</param>
        /// <param name="right">The right observable sequence to join elements for.</param>
        /// <param name="leftDurationSelector">A function to select the duration of each element of the left observable sequence, used to determine overlap.</param>
        /// <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);

View on GitHub (pinned to 94b5d5ab91)