dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'subscribeAsync')

Error message

Value cannot be null. (Parameter 'subscribeAsync')

What it means

The ToLookup operator validates its delegate arguments eagerly when the operator is built. A null valueSelector means the operator cannot project elements to values once the lookup aggregation starts, so System.Reactive.Async throws ArgumentNullException(nameof(valueSelector)) immediately at subscription-wiring time rather than failing later inside the aggregation. This fail-fast contract mirrors LINQ's own argument guards.

Solutions

  1. Pass a non-null Func<TSource,TValue> as the third argument to ToLookup
  2. If the selector is computed, check it for null before calling ToLookup
  3. If a no-op projection is intended, use x => x or the appropriate identity/select overload instead of null

Example fix

// before
var op = AsyncObservable.ToLookup(source, x => x.Key, (Func<Order, string>)null);
// after
var op = AsyncObservable.ToLookup(source, x => x.Key, x => x.Value);
Defensive patterns

Strategy: validation

Validate before calling

if (source is null) throw new ArgumentNullException(nameof(source));
if (keySelector is null) throw new ArgumentNullException(nameof(keySelector));
if (valueSelector is null) throw new ArgumentNullException(nameof(valueSelector));

Type guard

static bool IsValidToLookupArgs<TSource,TKey,TValue>(Func<TSource,ValueTask<TKey>> k, Func<TSource,ValueTask<TValue>> v) => k != null && v != null;

Try / catch

try
{
    var op = AsyncObservable.ToLookup(observer, keySelector, valueSelector);
}
catch (ArgumentNullException ex) when (ex.ParamName == "valueSelector")
{
    // supply a default selector or log configuration error
}

Prevention

When it happens

Trigger: Calling AsyncObservable.ToLookup(observer, keySelector, null) — the 3-argument overload with sync Func selectors, at ToLookup.cs:126.

Common situations: Passing the result of a conditional expression or a helper that returned null for the value selector; refactoring where a Func variable became null; reflection or DI-created delegates resolving to null.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/AsyncObservable.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.Threading.Tasks;

namespace System.Reactive
{
    public class AsyncObservable<T> : AsyncObservableBase<T>
    {
        private readonly Func<IAsyncObserver<T>, ValueTask<IAsyncDisposable>> _subscribeAsync;

        public AsyncObservable(Func<IAsyncObserver<T>, ValueTask<IAsyncDisposable>> subscribeAsync)
        {
            _subscribeAsync = subscribeAsync ?? throw new ArgumentNullException(nameof(subscribeAsync));
        }

        protected override ValueTask<IAsyncDisposable> SubscribeAsyncCore(IAsyncObserver<T> observer)
        {
            if (observer == null)
                throw new ArgumentNullException(nameof(observer));

            return _subscribeAsync(observer);
        }
    }
}

View on GitHub (pinned to 94b5d5ab91)