dotnet/reactive · error · ArgumentNullException

left

Error message

left

What it means

QueryableExtensions.And(left, right) combines an IQbservable left pattern with a right observable into a QueryablePattern; both operands must be non-null. The method throws ArgumentNullException("left") when the left IQbservable<TLeft> is null. Because this is the queryable (expression-tree) variant, the null check happens locally before the Expression.Call is built — a null left cannot be translated.

Solutions

  1. Ensure the left query is produced by a real IQbservableProvider (e.g. provider.CreateQuery) rather than null.
  2. Substitute an empty queryable sequence when the left side has no data.
  3. Null-check the left query before composing the And pattern.

Example fix

// before
IQbservable<int> left = GetLeftQuery(); // null
var pattern = left.And(right);
// after
IQbservable<int> left = GetLeftQuery() ?? provider.CreateQuery<int>(Observable.Empty<int>());
var pattern = left.And(right);
Defensive patterns

Strategy: validation

Validate before calling

if (left is null) throw new InvalidOperationException("left query must be created by an IQbservableProvider");
var pattern = left.And(right);

Type guard

bool HasLeftQuery<TL, TR>(IQbservable<TL>? l, IObservable<TR>? r) => l is not null && r is not null;

Try / catch

try { var pattern = left.And(right); }
catch (ArgumentNullException ex) when (ex.ParamName == "left") { /* rebuild left via provider.CreateQuery before retrying */ }

Prevention

When it happens

Trigger: Calling left.And(right) where left is a null IQbservable<TLeft>, e.g. chaining off a query provider method that returned null.

Common situations: Building join patterns in IQbservable-based (e.g. Rx over remote/IQbservableProvider) pipelines where an earlier query step returned null instead of an empty sequence.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Linq/Qbservable.Joins.cs:29

{
    public static partial class Qbservable
    {
        /* NOTE: Keep XML docs consistent with the corresponding Observable methods (modulo the IQbservableProvider parameters of course). */

        /// <summary>
        /// Creates a pattern that matches when both observable sequences have an available element.
        /// </summary>
        /// <typeparam name="TLeft">The type of the elements in the left sequence.</typeparam>
        /// <typeparam name="TRight">The type of the elements in the right sequence.</typeparam>
        /// <param name="left">Observable sequence to match with the right sequence.</param>
        /// <param name="right">Observable sequence to match with the left sequence.</param>
        /// <returns>Pattern object that matches when both observable sequences have an available element.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="left"/> or <paramref name="right"/> is null.</exception>
        public static QueryablePattern<TLeft, TRight> And<TLeft, TRight>(this IQbservable<TLeft> left, IObservable<TRight> right)
        {
            if (left == null)
            {
                throw new ArgumentNullException(nameof(left));
            }

            if (right == null)
            {
                throw new ArgumentNullException(nameof(right));
            }

            return new QueryablePattern<TLeft, TRight>(
                Expression.Call(
                    null,
                    new Func<IQbservable<TLeft>, IObservable<TRight>, QueryablePattern<TLeft, TRight>>(And).Method,
                    left.Expression,
                    GetSourceExpression(right)
                )
            );
        }

        /// <summary>

View on GitHub (pinned to 94b5d5ab91)