dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'source')

Error message

Value cannot be null. (Parameter 'source')

What it means

The parameterless-projection AsyncObservable.Max<TSource>(IAsyncObservable<TSource>) throws ArgumentNullException with parameter name 'source' when the input async observable is null. The library validates all operator inputs eagerly so the failure surfaces at composition time, not later during subscription. A null source has no meaningful Max semantics, so the throw is immediate.

Solutions

  1. Ensure the source is created with a non-null factory such as AsyncObservable.Return(...) or AsyncObservable.Empty(...) before calling Max.
  2. Guard at the call site: if (source == null) source = AsyncObservable.Empty<int>();
  3. Use the null-coalescing operator: AsyncObservable.Max(source ?? AsyncObservable.Empty<int>())

Example fix

// before
IAsyncObservable<int> source = maybeSource; // can be null
var max = AsyncObservable.Max(source);

// after
var max = AsyncObservable.Max(source ?? AsyncObservable.Empty<int>());
Defensive patterns

Strategy: validation

Validate before calling

if (source is null) source = AsyncObservable.Empty<TSource>();

Type guard

static bool HasSource<TSource>(IAsyncObservable<TSource>? s) => s is not null;

Try / catch

try { var max = AsyncObservable.Max(source); }
catch (ArgumentNullException ex) when (ex.ParamName == "source") { /* substitute Empty() or fix upstream factory */ }

Prevention

When it happens

Trigger: Calling AsyncObservable.Max(null) — typically a source variable that is null because an earlier factory/conditional expression produced null, or a method chain where the upstream Build/Return call was skipped.

Common situations: A pipeline assembled conditionally where the source assignment is missed on one branch; deserialized or DI-injected observables that failed to bind; storing IAsyncObservable in a field initialized lazily and read too early.

Related errors


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

Appendix: source

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

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT License.
// See the LICENSE file in the project root for more information. 

using System.Collections.Generic;
using System.Threading.Tasks;

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

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

        public static IAsyncObservable<TSource> Max<TSource>(IAsyncObservable<TSource> source, IComparer<TSource> comparer)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (comparer == null)
                throw new ArgumentNullException(nameof(comparer));

            return CreateAsyncObservable<TSource>.From(
                source,
                comparer,
                static (source, comparer, observer) => source.SubscribeSafeAsync(AsyncObserver.Max(observer, comparer)));
        }
    }

View on GitHub (pinned to 94b5d5ab91)