dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'source')
Error message
Value cannot be null. (Parameter 'source')
What it means
The Switch extension operator requires a non-null source observable of inner observables. It throws ArgumentNullException at composition time (Switch.cs:15) so that a null source fails immediately at the call site rather than surfacing as a NullReferenceException deep inside SubscribeAsync. This is standard defensive validation across all AsyncRx operators.
Solutions
- Verify the outer observable is non-null before invoking .Switch()
- Check any factory/cache lookup that produced the source and handle its null return before chaining
- Add a null check or throw a descriptive exception at the pipeline construction site
- Restructure so the inner observables are produced by a non-null source (e.g. Select over an existing sequence)
Example fix
// before
var merged = maybeSource.Switch(); // NRE/ANRE when maybeSource is null
// after
if (maybeSource == null) throw new InvalidOperationException("inner source not initialized");
var merged = maybeSource.Switch(); Defensive patterns
Strategy: validation
Validate before calling
if (source is null)
throw new InvalidOperationException("Switch requires a non-null source of inner observables.");
var merged = source.Switch(); Type guard
static bool HasSource<T>(IAsyncObservable<IAsyncObservable<T>>? s) => s is not null;
Try / catch
try
{
var merged = source.Switch();
}
catch (ArgumentNullException ex) when (ex.ParamName == "source")
{
logger.LogError(ex, "Switch called with null source; check the upstream factory/lookup");
} Prevention
- Check the null-ability of factory results before chaining extension operators
- Use nullable reference type annotations so a null source is caught at compile time
- Fail fast at pipeline construction with descriptive exceptions instead of letting guards fire
- Avoid memoization patterns that can cache null results for observables
When it happens
Trigger: Calling source.Switch() where source is a null IAsyncObservable<IAsyncObservable<T>>, e.g. a factory method or dictionary lookup that returned null before being chained with .Switch().
Common situations: Chaining Switch onto the result of another operator or a memoized cache entry that is null; refactoring where an observable field was renamed or not yet assigned; conditional pipeline construction where a branch forgot to assign the source.
Related errors
- Value cannot be null. (Parameter 'observer')
- Value cannot be null. (Parameter 'source')
- Value cannot be null. (Parameter 'observer')
- nameof(observer)
- nameof(observer)
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/9050d25f45eb1041.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Switch.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.Disposables;
using System.Threading;
namespace System.Reactive.Linq
{
public partial class AsyncObservable
{
public static IAsyncObservable<TSource> Switch<TSource>(this IAsyncObservable<IAsyncObservable<TSource>> source)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
return Create<IAsyncObservable<TSource>, TSource>(
source,
async static (source, observer) =>
{
var (sink, cancel) = AsyncObserver.Switch(observer);
var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false);
return StableCompositeAsyncDisposable.Create(subscription, cancel);
});
}
}
public partial class AsyncObserver
{
public static (IAsyncObserver<IAsyncObservable<TSource>>, IAsyncDisposable) Switch<TSource>(IAsyncObserver<TSource> observer)
{View on GitHub (pinned to 94b5d5ab91)