dotnet/reactive · error · ArgumentNullException

ArgumentNullException

Error message

ArgumentNullException

What it means

This generated Max overload (selector returning long?) validates its inputs up front: both the source sequence and the selector delegate must be non-null. Passing null for either throws ArgumentNullException before any subscription is created.

Solutions

  1. Ensure the source IAsyncObservable is non-null before calling Max
  2. Ensure the selector delegate is a non-null method group or lambda
  3. If the source can be null in your flow, coalesce to an empty observable (e.g. AsyncObservable.Empty<TSource>())

Example fix

// before
Func<string, long?> sel = null;
var max = await source.Max(sel); // ArgumentNullException
// after
var max = await source.Max((string x) => (long?)x.Length);
Defensive patterns

Strategy: validation

Validate before calling

if (source is null) throw new ArgumentNullException(nameof(source));
if (selector is null) throw new ArgumentNullException(nameof(selector));
var max = await source.Max(selector);

Type guard

static bool CanMax<TSource>(IAsyncObservable<TSource>? s, Func<TSource, long?>? sel) => s is not null && sel is not null;

Try / catch

try
{
    var max = await source.Max(selector);
}
catch (ArgumentNullException ex) when (ex.ParamName is "source" or "selector")
{
    max = null; // or log and use a default
}

Prevention

When it happens

Trigger: Calling Max<TSource>(source, Func<TSource, long?> selector) with source == null or selector == null, e.g. await null.Max(x => (long?)x.Length) or a null delegate variable.

Common situations: Chaining Max onto a method whose result was null; passing a selector captured from an uninitialized field; null propagating from an earlier failed lookup before the aggregate call.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Max.Generated.cs:126

                source,
                selector,
                static (source, selector, observer) => source.SubscribeSafeAsync(AsyncObserver.MaxInt64(observer, selector)));
        }

        public static IAsyncObservable<Int64?> Max(this IAsyncObservable<Int64?> source)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));

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

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

            return CreateAsyncObservable<Int64?>.From(
                source,
                selector,
                static (source, selector, observer) => source.SubscribeSafeAsync(AsyncObserver.MaxNullableInt64(observer, selector)));
        }

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

            return CreateAsyncObservable<Int64?>.From(
                source,
                selector,
                static (source, selector, observer) => source.SubscribeSafeAsync(AsyncObserver.MaxNullableInt64(observer, selector)));

View on GitHub (pinned to 94b5d5ab91)