dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'observer')
Error message
Value cannot be null. (Parameter 'observer')
What it means
AsyncObserver.Switch is the low-level sink factory for the Switch operator and validates that the downstream observer is non-null, throwing ArgumentNullException at Switch.cs:35. It guards the state machine (gate, hasLatest, latest tracking) that would otherwise capture a null observer and fail on the first OnNextAsync notification.
Solutions
- Pass a valid IAsyncObserver<TSource> obtained from your subscription context
- If writing a custom operator, validate the observer yourself before delegating to AsyncObserver.Switch
- Prefer the public source.Switch() extension, which wires up a real observer automatically
Example fix
// before var (sink, cancel) = AsyncObserver.Switch<TSource>(observer); // observer may be null // after if (observer == null) throw new ArgumentNullException(nameof(observer)); var (sink, cancel) = AsyncObserver.Switch<TSource>(observer);
Defensive patterns
Strategy: validation
Validate before calling
if (observer is null)
throw new ArgumentNullException(nameof(observer));
var (sink, cancel) = AsyncObserver.Switch(observer); Type guard
static bool HasObserver<T>(IAsyncObserver<T>? o) => o is not null;
Try / catch
try
{
var (sink, cancel) = AsyncObserver.Switch(observer);
}
catch (ArgumentNullException ex) when (ex.ParamName == "observer")
{
// custom-operator wiring bug: the downstream observer was never supplied
logger.LogError(ex, "AsyncObserver.Switch requires a non-null observer");
} Prevention
- When writing custom operators, validate observer parameters before delegating to AsyncObserver.* primitives
- Prefer public extension operators (source.Switch()) over hand-wiring AsyncObserver sinks
- Keep observer arguments non-nullable in your own signatures to surface bugs at compile time
When it happens
Trigger: Calling AsyncObserver.Switch<TSource>(null) directly, or a custom Create(...) composition that passes a null observer into AsyncObserver.Switch.
Common situations: Writing custom operators on top of AsyncObserver primitives where the observer parameter flows through unvalidated; unit tests passing null to exercise guard clauses.
Related errors
- Value cannot be null. (Parameter 'source')
- Value cannot be null. (Parameter 'onNextAsync')
- 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/262eaca775d7880d.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Switch.cs:35
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)
{
if (observer == null)
throw new ArgumentNullException(nameof(observer));
var gate = new AsyncGate();
var isStopped = false;
var hasLatest = false;
var latest = 0UL;
var disposable = new SerialAsyncDisposable();
return
(
Create<IAsyncObservable<TSource>>(
async xs =>
{
ulong id;
using (await gate.LockAsync().ConfigureAwait(false))
{View on GitHub (pinned to 94b5d5ab91)