dotnet/reactive · error · ArgumentNullException

throw new ArgumentNullException(nameof(func));

Error message

throw new ArgumentNullException(nameof(func));

What it means

The Scan(source, func) sync accumulator overload throws ArgumentNullException because the func argument was null. System.Reactive.Async operators validate all arguments eagerly at call time so misconfiguration surfaces immediately instead of failing inside the subscription pipeline. A null accumulator cannot combine elements, so the operator refuses to be constructed.

Solutions

  1. Pass a non-null accumulator, e.g. source.Scan((acc, x) => acc + x).
  2. Check the variable holding the delegate for null before calling Scan and provide a default.
  3. If the accumulator may legitimately be absent, guard with source.Scan(func ?? DefaultCombine) or skip Scan entirely.

Example fix

// before
Func<int, int, int> combine = null;
var scanned = source.Scan(combine); // throws ArgumentNullException

// after
Func<int, int, int> combine = (acc, x) => acc + x;
var scanned = source.Scan(combine);
Defensive patterns

Strategy: validation

Validate before calling

if (func is null) throw new InvalidOperationException("Scan accumulator must be configured before use");
var scanned = source.Scan(func);

Type guard

static bool IsValidAccumulator<TSource>(Func<TSource, TSource, TSource> f) => f is not null;

Try / catch

try { var scanned = source.Scan(func); }
catch (ArgumentNullException ex) when (ex.ParamName == "func") { /* substitute a default accumulator or abort pipeline setup */ }

Prevention

When it happens

Trigger: Calling source.Scan(null) where source is a non-null IAsyncObservable<TSource> but the Func<TSource,TSource,TSource> accumulator literal is null (e.g. a null-valued variable, field, or method return).

Common situations: Passing a accumulator delegate stored in a nullable field that was never assigned; receiving a null callback from a factory or configuration lookup; conditional delegate wiring where a branch left func unset.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Scan.cs:16

// 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.Threading.Tasks;

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

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

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

            return CreateAsyncObservable<TSource>.From(
                source,
                func,
                static (source, func, observer) => source.SubscribeSafeAsync(AsyncObserver.Scan(observer, func)));

View on GitHub (pinned to 94b5d5ab91)