dotnet/reactive · error · ArgumentNullException

third

Error message

third

What it means

This ArgumentNullException is thrown by QbservableEx.CombineLatest<TFirst,TSecond,TThird> because the third source sequence was null. The Qbservable extensions eagerly validate all source arguments before building the expression tree via CreateQuery, since a null expression source cannot be represented in the IQueryable provider model. It is a fail-fast contract guard, not a runtime data error.

Solutions

  1. Pass a valid IObservable<TThird>, e.g. Observable.Empty<TThird>() or Observable.Never<TThird>() instead of null.
  2. Fix the producer of the third argument so it returns a non-null sequence.
  3. Add a null check / coalesce before calling CombineLatest.

Example fix

// before
var combined = source.CombineLatest(a, b /* b is null */);
// after
var combined = source.CombineLatest(a, b ?? Observable.Empty<int>());
Defensive patterns

Strategy: validation

Validate before calling

if (first == null || second == null || third == null) throw new InvalidOperationException("CombineLatest sources must all be non-null; use Observable.Empty<T>() instead.");

Type guard

static bool AllNonNull<T1, T2, T3>(T1 a, T2 b, T3 c) where T1 : class where T2 : class where T3 : class => a != null && b != null && c != null;

Try / catch

try { var combined = first.CombineLatest(second, third); } catch (ArgumentNullException ex) { logger.LogError(ex, "Null CombineLatest source: {Param}", ex.ParamName); }

Prevention

When it happens

Trigger: Calling CombineLatest(first, second, third) on IQbservable<TFirst> with third == null, e.g. passing the result of a method that returned null instead of an empty IObservable<TThird>.

Common situations: Chaining observable factories whose return values are not null-checked; refactoring Rx code to Qbservable code where a null 'no source' value previously slipped through; conditional pipelines where a later source is only assigned in some branches.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Linq/QbservableEx.Homoicon.cs:68

        /// Merges the specified observable sequences into one observable sequence of tuple values whenever any of the observable sequences produces an element.
        /// </summary>
        /// <typeparam name="TFirst">The type of the elements in the first source sequence.</typeparam>
        /// <typeparam name="TSecond">The type of the elements in the second source sequence.</typeparam>
        /// <typeparam name="TThird">The type of the elements in the third source sequence.</typeparam>
        /// <param name="first">First observable source.</param>
        /// <param name="second">Second observable source.</param>
        /// <param name="third">Third observable source.</param>
        /// <returns>An observable sequence containing the result of combining elements of the sources using tuple values.</returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="first" /> or <paramref name="second" /> or <paramref name="third" /> is null.</exception>
        public static IQbservable<(TFirst First, TSecond Second, TThird Third)> CombineLatest<TFirst, TSecond, TThird>(this IQbservable<TFirst> first, IObservable<TSecond> second, IObservable<TThird> third)
        {
            if (first == null)
                throw new ArgumentNullException(nameof(first));
            if (second == null)
                throw new ArgumentNullException(nameof(second));
            if (third == null)
                throw new ArgumentNullException(nameof(third));

            return first.Provider.CreateQuery<(TFirst First, TSecond Second, TThird Third)>(
                Expression.Call(
                    null,
                    new Func<IQbservable<TFirst>, IObservable<TSecond>, IObservable<TThird>, IQbservable<(TFirst First, TSecond Second, TThird Third)>>(CombineLatest<TFirst, TSecond, TThird>).Method,
                    first.Expression,
                    GetSourceExpression(second),
                    GetSourceExpression(third)
                )
            );
        }

        /// <summary>
        /// Merges the specified observable sequences into one observable sequence of tuple values whenever any of the observable sequences produces an element.
        /// </summary>
        /// <typeparam name="TFirst">The type of the elements in the first source sequence.</typeparam>
        /// <typeparam name="TSecond">The type of the elements in the second source sequence.</typeparam>
        /// <typeparam name="TThird">The type of the elements in the third source sequence.</typeparam>

View on GitHub (pinned to 94b5d5ab91)