dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'sources')

Error message

Value cannot be null. (Parameter 'sources')

What it means

Thrown by Case<TValue, TResult>(selector, sources, defaultSource) when the sources dictionary is null. Case looks up the selector's value in this IDictionary to choose the source observable; without the dictionary there is nothing to dispatch to, so the operator rejects null eagerly.

Solutions

  1. Build and pass a non-empty sources dictionary (keys matching selector outputs).
  2. Ensure the registry/dictionary is initialized before composing the pipeline.
  3. Use the dictionary-preserving overload Case(selector, sources, scheduler) if a default isn't needed, but still pass a non-null map.

Example fix

// before
var stream = Case(selector, sourceMap, empty); // sourceMap null before init
// after
var map = sourceMap ?? new Dictionary<Key, IAsyncObservable<Result>>();
var stream = Case(selector, map, empty);
Defensive patterns

Strategy: validation

Validate before calling

if (sources is null) throw new ArgumentNullException(nameof(sources));

Type guard

bool HasSources<TValue, TResult>(IDictionary<TValue, IAsyncObservable<TResult>>? d) => d is { Count: > 0 };

Try / catch

try { var s = Case(selector, sources, defaultSource); }
catch (ArgumentNullException ex) when (ex.ParamName == "sources") { /* initialize registry */ }

Prevention

When it happens

Trigger: Calling Case(selector, sources, defaultSource) with a null IDictionary<TValue, IAsyncObservable<TResult>>, often a dictionary built lazily or from a config registry that failed to load.

Common situations: Source registry populated at startup but accessed before initialization; DI not providing the mapping; refactoring renamed the dictionary field leaving it null.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Case.cs:22

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;
                    }
                }
                catch (Exception ex)
                {

View on GitHub (pinned to 94b5d5ab91)