dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'source')
Error message
Value cannot be null. (Parameter 'source')
What it means
In the comparer-overload of ToLookup, the valueSelector is checked after observer and keySelector. Passing a null valueSelector prevents projecting element values into the Lookup<TKey,TValue> accumulator built via Aggregate, so ArgumentNullException(nameof(valueSelector)) is thrown at composition time (ToLookup.cs:138).
Solutions
- Pass a non-null Func<TSource,ValueTask<TValue>> as the value selector
- Guard computed delegates with a null check before composing
- Use x => x to keep whole elements as values instead of null
Example fix
// before var op = AsyncObservable.ToLookup(sink, x => x.CustomerId, null, comparer); // after var op = AsyncObservable.ToLookup(sink, x => x.CustomerId, x => x.Name, comparer);
Defensive patterns
Strategy: validation
Validate before calling
if (keySelector is null) throw new ArgumentNullException(nameof(keySelector)); if (valueSelector is null) throw new ArgumentNullException(nameof(valueSelector));
Type guard
static bool ValidSelectors<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, comparer);
}
catch (ArgumentNullException ex) when (ex.ParamName == "valueSelector")
{
// fall back to identity selector or report configuration error
} Prevention
- Treat all Func arguments to Rx operators as required, never optional
- When conditionally choosing selectors, always assign a default in the else branch
- Enable nullable reference types to catch potentially-null delegate variables at compile time
When it happens
Trigger: Calling AsyncObservable.ToLookup(observer, keySelector, null, comparer) — 4-argument overload.
Common situations: Value selector supplied conditionally (only for some overloads); a projected delegate stored in a field that was never assigned; copy-paste between overloads dropping one argument.
Related errors
- Value cannot be null. (Parameter 'subscribeAsync')
- Value cannot be null. (Parameter 'observer')
- Value cannot be null. (Parameter 'observer')
- Value cannot be null. (Parameter 'onNextAsync')
- ArgumentNullException: subscription
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/32516fc52a166bf0.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/AsyncObservableExtensions.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.Reactive;
using System.Threading.Tasks;
namespace System
{
public static class AsyncObservableExtensions
{
public static ValueTask<IAsyncDisposable> SubscribeAsync<T>(this IAsyncObservable<T> source, Func<T, ValueTask> onNextAsync)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (onNextAsync == null)
throw new ArgumentNullException(nameof(onNextAsync));
return source.SubscribeAsync(new AsyncObserver<T>(onNextAsync, ex => new ValueTask(Task.FromException(ex)), () => default));
}
public static ValueTask<IAsyncDisposable> SubscribeAsync<T>(this IAsyncObservable<T> source, Func<T, ValueTask> onNextAsync, Func<Exception, ValueTask> onErrorAsync)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (onNextAsync == null)
throw new ArgumentNullException(nameof(onNextAsync));
if (onErrorAsync == null)
throw new ArgumentNullException(nameof(onErrorAsync));
return source.SubscribeAsync(new AsyncObserver<T>(onNextAsync, onErrorAsync, () => default));
}
View on GitHub (pinned to 94b5d5ab91)