dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'functionAsync')

Error message

Value cannot be null. (Parameter 'functionAsync')

What it means

Observable.StartAsync<TResult>(Func<Task<TResult>> functionAsync) throws ArgumentNullException when the async factory delegate is null. The delegate is the core of the operation — it produces the Task whose result the observable emits — so the library fails fast rather than producing an observable that errors only on subscribe.

Solutions

  1. Ensure the Func<Task<TResult>> delegate is assigned before calling StartAsync
  2. If the delegate is looked up, validate the lookup result and throw a clearer error
  3. Prefer passing the async method group directly (e.g. StartAsync(DoWorkAsync)) instead of a variable

Example fix

// before
Func<Task<int>> f = registry.GetHandler(name); // may be null
Observable.StartAsync(f);
// after
Func<Task<int>> f = registry.GetHandler(name) ?? throw new InvalidOperationException($"no handler for {name}");
Observable.StartAsync(f);
Defensive patterns

Strategy: validation

Validate before calling

if (functionAsync == null) throw new ArgumentNullException(nameof(functionAsync));
Observable.StartAsync(functionAsync);

Type guard

bool IsValidAsync(Func<Task<TResult>> f) => f is not null;

Try / catch

try { Observable.StartAsync(functionAsync); }
catch (ArgumentNullException ex) when (ex.ParamName == "functionAsync") { log.LogError("StartAsync requires a non-null async delegate"); throw; }

Prevention

When it happens

Trigger: Calling Observable.StartAsync with a null Func<Task<TResult>>, e.g. an unassigned async lambda variable or a null returned from a strategy/registry lookup of async work.

Common situations: Conditional assignment of an async delegate, storing Func<Task<T>> in a nullable field populated asynchronously, or reflection-based delegate construction that silently failed.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.Async.cs:1043

        /// <summary>
        /// Invokes the asynchronous function, surfacing the result through an observable sequence.
        /// </summary>
        /// <typeparam name="TResult">The type of the result returned by the asynchronous function.</typeparam>
        /// <param name="functionAsync">Asynchronous function to run.</param>
        /// <returns>An observable sequence exposing the function's result value, or an exception.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="functionAsync"/> is null.</exception>
        /// <remarks>
        /// <list type="bullet">
        /// <item><description>The function is started immediately, not during the subscription of the resulting sequence.</description></item>
        /// <item><description>Multiple subscriptions to the resulting sequence can observe the function's result.</description></item>
        /// </list>
        /// </remarks>
        public static IObservable<TResult> StartAsync<TResult>(Func<Task<TResult>> functionAsync)
        {
            if (functionAsync == null)
            {
                throw new ArgumentNullException(nameof(functionAsync));
            }

            return s_impl.StartAsync(functionAsync);
        }

        /// <summary>
        /// Invokes the asynchronous function, surfacing the result through an observable sequence.
        /// </summary>
        /// <typeparam name="TResult">The type of the result returned by the asynchronous function.</typeparam>
        /// <param name="functionAsync">Asynchronous function to run.</param>
        /// <param name="scheduler">Scheduler on which to notify observers.</param>
        /// <returns>An observable sequence exposing the function's result value, or an exception.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="functionAsync"/> is null or <paramref name="scheduler"/> is null.</exception>
        /// <remarks>
        /// <list type="bullet">
        /// <item><description>The function is started immediately, not during the subscription of the resulting sequence.</description></item>
        /// <item><description>Multiple subscriptions to the resulting sequence can observe the function's result.</description></item>
        /// </list>

View on GitHub (pinned to 94b5d5ab91)