dotnet/reactive · error · ArgumentNullException

plans

Error message

plans

What it means

When<TResult>(params QueryablePlan<TResult>[] plans) requires a non-null plans array to match against; the method throws ArgumentNullException("plans") when the array itself is null. Note the params array must exist even if empty (an empty array is accepted, null is not), because the plans are embedded into the Expression.Call for the remote/queryable When operator.

Solutions

  1. Pass at least one QueryablePlan, or an empty array instead of null: provider.When(Array.Empty<QueryablePlan<TResult>>()).
  2. Null-check the plans collection and fall back to an empty plan set or an empty result query.
  3. Fix the code that assembles the plans so it always produces a non-null array.

Example fix

// before
QueryablePlan<string>[] plans = BuildPlans(); // null
var result = provider.When(plans);
// after
QueryablePlan<string>[] plans = BuildPlans() ?? Array.Empty<QueryablePlan<string>>();
var result = provider.When(plans);
Defensive patterns

Strategy: validation

Validate before calling

if (plans is null) plans = Array.Empty<QueryablePlan<TResult>>();
var result = provider.When(plans);

Type guard

bool HasPlans<TResult2>(QueryablePlan<TResult2>[]? p) => p is not null;

Try / catch

try { var result = provider.When(plans); }
catch (ArgumentNullException ex) when (ex.ParamName == "plans") { var result = provider.When(Array.Empty<QueryablePlan<TResult>>()); }

Prevention

When it happens

Trigger: Calling provider.When(null) explicitly, or passing a QueryablePlan<TResult>[] variable that is null (e.g. result of a failed lookup or uninitialized field).

Common situations: Dynamically building plans where the plan collection is assembled conditionally and ends up null at the call site; calling When with a null plans variable instead of an empty array.

Related errors


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

Appendix: source

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

        /// <summary>
        /// Joins together the results from several patterns.
        /// </summary>
        /// <typeparam name="TResult">The type of the elements in the result sequence, obtained from the specified patterns.</typeparam>
        /// <param name="provider">Query provider used to construct the <see cref="IQbservable{T}"/> data source.</param>
        /// <param name="plans">A series of plans created by use of the Then operator on patterns.</param>
        /// <returns>An observable sequence with the results from matching several patterns.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="provider"/> or <paramref name="plans"/> is null.</exception>
        public static IQbservable<TResult> When<TResult>(this IQbservableProvider provider, params QueryablePlan<TResult>[] plans)
        {
            if (provider == null)
            {
                throw new ArgumentNullException(nameof(provider));
            }

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

            return provider.CreateQuery<TResult>(
                Expression.Call(
                    null,
                    new Func<IQbservableProvider, QueryablePlan<TResult>[], IQbservable<TResult>>(When).Method,
                    Expression.Constant(provider, typeof(IQbservableProvider)),
                    Expression.NewArrayInit(
                        typeof(QueryablePlan<TResult>),
                        plans.Select(p => p.Expression)
                    )
                )
            );
        }

        /// <summary>
        /// Joins together the results from several patterns.
        /// </summary>

View on GitHub (pinned to 94b5d5ab91)