dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'selector')
Error message
Value cannot be null. (Parameter 'selector')
What it means
Thrown by the Case operator (Case(selector, sources, defaultSource), reached via the scheduler overload too) when the selector function is null. Case calls selector per subscription to pick which source observable from the dictionary to subscribe to; a null selector would crash at subscribe time, so it is validated when the operator is built.
Solutions
- Pass a concrete selector, e.g. () => settings.Mode or () => key.
- Coalesce with a default key function: selector ?? (() => defaultKey).
- Validate the delegate at construction of your pipeline, before composing Case.
Example fix
// before var stream = Case(modeSelector, sources, defaultSource); // modeSelector null // after var sel = modeSelector ?? (() => ModeKey.Default); var stream = Case(sel, sources, defaultSource);
Defensive patterns
Strategy: validation
Validate before calling
if (selector is null) throw new ArgumentNullException(nameof(selector));
Type guard
bool HasSelector<TValue>(Func<TValue>? f) => f is not null;
Try / catch
try { var s = Case(selector, sources, defaultSource); }
catch (ArgumentNullException ex) when (ex.ParamName == "selector") { /* provide selector */ } Prevention
- Store key selectors as required (non-nullable) constructor dependencies
- Coalesce with a default key function when optional
- Resolve DI-injected delegates before composing the observable chain
When it happens
Trigger: Calling Case<TValue, TResult>(selector, sources, scheduler) or Case(selector, sources, defaultSource) with selector == null, e.g. a delegate resolved from DI/config that is null.
Common situations: Key-selector delegates stored in nullable fields; switching logic where the mode function was removed in a refactor; test doubles returning null selectors.
Related errors
- Value cannot be null. (Parameter 'sources')
- Value cannot be null. (Parameter 'defaultSource')
- Value cannot be null. (Parameter 'onErrorAsync')
- Value cannot be null. (Parameter 'onCompletedAsync')
- Value cannot be null. (Parameter 'error')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/863378feb5543f6a.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Case.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.Reactive.Concurrency;
using System.Threading.Tasks;
namespace System.Reactive.Linq
{
public partial class AsyncObservable
{
public static IAsyncObservable<TResult> Case<TValue, TResult>(Func<TValue> selector, IDictionary<TValue, IAsyncObservable<TResult>> sources) => Case(selector, sources, Empty<TResult>());
public static IAsyncObservable<TResult> Case<TValue, TResult>(Func<TValue> selector, IDictionary<TValue, IAsyncObservable<TResult>> sources, IAsyncScheduler scheduler) => Case(selector, sources, Empty<TResult>(scheduler));
public static IAsyncObservable<TResult> Case<TValue, TResult>(Func<TValue> selector, IDictionary<TValue, IAsyncObservable<TResult>> sources, IAsyncObservable<TResult> defaultSource)
{
if (selector == null)
throw new ArgumentNullException(nameof(selector));
if (sources == null)
throw new ArgumentNullException(nameof(sources));
if (defaultSource == null)
throw new ArgumentNullException(nameof(defaultSource));
return Create<TResult>(observer =>
{
var source = default(IAsyncObservable<TResult>);
try
{
var value = selector();
if (!sources.TryGetValue(value, out source))
{
source = defaultSource;
}
}View on GitHub (pinned to 94b5d5ab91)