dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'selector')

Error message

Value cannot be null. (Parameter 'selector')

What it means

The generated Sum(source, selector) operator validates both arguments and throws ArgumentNullException with the full framework message "Value cannot be null. (Parameter 'selector')" when the projection delegate is null. The selector is required to convert each element to Int32 before aggregation.

Solutions

  1. Pass a concrete selector, e.g. source.Sum(x => x.Amount).
  2. Fix the null delegate source (DI registration, field initialization, method group signature).
  3. If no projection is needed, call the selector-less Sum() overload.

Example fix

// before
Func<Order, int> sel = null;
var total = orders.Sum(sel);
// after
var total = orders.Sum(o => o.Amount);
Defensive patterns

Strategy: validation

Validate before calling

if (selector == null)
    throw new ArgumentNullException(nameof(selector));
var total = source.Sum(selector);

Type guard

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

Try / catch

try
{
    var total = await source.Sum(selector);
}
catch (ArgumentNullException ex) when (ex.ParamName == "selector")
{
    logger.LogError(ex, "Null selector passed to Sum");
    total = 0;
}

Prevention

When it happens

Trigger: Calling source.Sum(null) or passing a selector variable that is null — e.g. a Func stored in config/DI that was never registered, or a method group that failed to bind (wrong signature).

Common situations: A delegate field initialized lazily and read too early; a method-group reference removed in a refactor; JSON/deserialized pipelines where delegates can't be expressed and default to null.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Sum.Generated.cs:24

namespace System.Reactive.Linq
{
    public partial class AsyncObservable
    {
        public static IAsyncObservable<Int32> Sum(this IAsyncObservable<Int32> source)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));

            return Create(source, static (source, observer) => source.SubscribeSafeAsync(AsyncObserver.SumInt32(observer)));
        }

        public static IAsyncObservable<Int32> Sum<TSource>(this IAsyncObservable<TSource> source, Func<TSource, Int32> selector)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (selector == null)
                throw new ArgumentNullException(nameof(selector));

            return CreateAsyncObservable<Int32>.From(
                source,
                selector,
                static (source, selector, observer) => source.SubscribeSafeAsync(AsyncObserver.SumInt32(observer, selector)));
        }

        public static IAsyncObservable<Int32> Sum<TSource>(this IAsyncObservable<TSource> source, Func<TSource, ValueTask<Int32>> selector)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (selector == null)
                throw new ArgumentNullException(nameof(selector));

            return CreateAsyncObservable<Int32>.From(
                source,
                selector,
                static (source, selector, observer) => source.SubscribeSafeAsync(AsyncObserver.SumInt32(observer, selector)));

View on GitHub (pinned to 94b5d5ab91)