dotnet/reactive · error · ArgumentNullException

ArgumentNullException(nameof(valueSelector))

Error message

ArgumentNullException(nameof(valueSelector))

What it means

ToLookup uses valueSelector to project each element into the value stored under its lookup key. Passing null throws ArgumentNullException(Parameter 'valueSelector') synchronously at the call site. The library checks source, keySelector, and valueSelector in order, so this guard fires only when the first two are valid.

Solutions

  1. Pass an explicit value projection, e.g. x => x.Value or x => x itself.
  2. Validate dynamically resolved selectors before calling ToLookup.
  3. If identity projection was intended, use the source element directly (x => x).

Example fix

// before
var lookup = source.ToLookup(x => x.Key, valueSelector); // valueSelector null
// after
var lookup = source.ToLookup(x => x.Key, x => x.Val);
Defensive patterns

Strategy: validation

Validate before calling

if (valueSelector == null) throw new ArgumentException("valueSelector must be provided", nameof(valueSelector));

Type guard

bool IsValidValueSelector<T,TValue>(Func<T,TValue> f) => f is not null;

Try / catch

try { var lookup = await source.ToLookup(keySelector, valueSelector); } catch (ArgumentNullException ex) when (ex.ParamName == "valueSelector") { /* supply identity or default projection */ }

Prevention

When it happens

Trigger: Calling ToLookup(source, keySelector, null) — the value-projection delegate is null while source and keySelector are valid.

Common situations: Query builders that assemble selectors from user input/configuration where the value mapping was omitted; copy-paste refactorings that dropped the value lambda.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/ToLookup.cs:20

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

namespace System.Reactive.Linq
{
    public partial class AsyncObservable
    {
        public static IAsyncObservable<ILookup<TKey, TValue>> ToLookup<TSource, TKey, TValue>(this IAsyncObservable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TValue> valueSelector)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (keySelector == null)
                throw new ArgumentNullException(nameof(keySelector));
            if (valueSelector == null)
                throw new ArgumentNullException(nameof(valueSelector));

            return CreateAsyncObservable<ILookup<TKey, TValue>>.From(
                source,
                (keySelector, valueSelector),
                static (source, state, observer) => source.SubscribeSafeAsync(AsyncObserver.ToLookup(observer, state.keySelector, state.valueSelector)));
        }

        public static IAsyncObservable<ILookup<TKey, TValue>> ToLookup<TSource, TKey, TValue>(this IAsyncObservable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TValue> valueSelector, IEqualityComparer<TKey> comparer)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (keySelector == null)
                throw new ArgumentNullException(nameof(keySelector));
            if (valueSelector == null)
                throw new ArgumentNullException(nameof(valueSelector));
            if (comparer == null)
                throw new ArgumentNullException(nameof(comparer));

View on GitHub (pinned to 94b5d5ab91)