dotnet/reactive · error · ArgumentNullException

Thrown when selector is null (ArgumentNullException, param…

Error message

Thrown when selector is null (ArgumentNullException, param name: selector)

What it means

Expand recursively applies a selector to grow the sequence; a null selector would terminate the recursion logic, so ArgumentNullException for parameter 'selector' is thrown. Fix: pass a non-null Func<TSource, IEnumerable<TSource>>.

Solutions

  1. Pass a real Func<TSource, IEnumerable<TSource>>; use _ => Enumerable.Empty<TSource>() for a no-expansion default.
  2. Ensure the delegate is initialized/injected before the call.
  3. Guard the delegate acquisition point.

Example fix

// before
var all = source.Expand(selector); // selector may be null
// after
var all = source.Expand(selector ?? (_ => Enumerable.Empty<Node>()));
Defensive patterns

Strategy: validation

Validate before calling

if (selector is null) throw new ArgumentNullException(nameof(selector));
Expand(source, selector ?? (_ => Enumerable.Empty<TSource>()));

Type guard

bool HasSelector<TSource>(Func<TSource, IEnumerable<TSource>> f) => f is not null;

Try / catch

try { var q = source.Expand(selector); }
catch (ArgumentNullException ex) when (ex.ParamName == "selector") { /* supply default selector */ }

Prevention

When it happens

Trigger: Calling Expand(source, null) — e.g. the selector delegate was resolved from configuration or a nullable member that is null.

Common situations: A strategy/visitor delegate not injected; conditional wiring that skips assigning the selector; using obj?.Selector which yields null.

Related errors


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

Appendix: source

Thrown at Ix.NET/Source/System.Interactive/System/Linq/Operators/Expand.cs:23

using System.Collections.Generic;

namespace System.Linq
{
    public static partial class EnumerableEx
    {
        /// <summary>
        /// Expands the sequence by recursively applying a selector function.
        /// </summary>
        /// <typeparam name="TSource">Source sequence element type.</typeparam>
        /// <param name="source">Source sequence.</param>
        /// <param name="selector">Selector function to retrieve the next sequence to expand.</param>
        /// <returns>Sequence with results from the recursive expansion of the source sequence.</returns>
        public static IEnumerable<TSource> Expand<TSource>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TSource>> selector)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (selector == null)
                throw new ArgumentNullException(nameof(selector));

            return ExpandCore(source, selector);
        }

        private static IEnumerable<TSource> ExpandCore<TSource>(IEnumerable<TSource> source, Func<TSource, IEnumerable<TSource>> selector)
        {
            var queue = new Queue<IEnumerable<TSource>>();
            queue.Enqueue(source);

            while (queue.Count > 0)
            {
                var src = queue.Dequeue();

                foreach (var item in src)
                {
                    queue.Enqueue(selector(item));
                    yield return item;
                }

View on GitHub (pinned to 94b5d5ab91)