dotnet/reactive · error · ArgumentNullException
observer
Error message
observer
What it means
The internal AsyncObserver.Join factory throws ArgumentNullException because the downstream IAsyncObserver<TResult> was null. This factory builds the paired left/right observers used by the Join operator; a null observer means results would have nowhere to go. The guard exists so the internal wiring always has a valid downstream sink.
Solutions
- Pass the actual downstream IAsyncObserver<TResult> instance as the first argument.
- In custom operator code, ensure the observer received in your subscription lambda is forwarded, not discarded.
- If you need a no-op sink for tests, provide a stub observer implementation rather than null.
Example fix
// before var (lo, ro, disp) = AsyncObserver.Join(null, subs, lds, rds, rs); // after var (lo, ro, disp) = AsyncObserver.Join(downstreamObserver, subs, lds, rds, rs);
Defensive patterns
Strategy: validation
Validate before calling
if (observer is null) throw new ArgumentException("downstream observer is required", nameof(observer)); Type guard
bool ObserverReady<T>(IAsyncObserver<T>? o) => o is not null;
Try / catch
try { var parts = AsyncObserver.Join(observer, subs, lds, rds, rs); }
catch (ArgumentNullException ex) when (ex.ParamName == "observer") { /* fix custom plumbing to forward downstream observer */ } Prevention
- In custom operators, always forward the observer given to your Subscribe lambda.
- Never pass null as an observer in tests; write a recording stub instead.
- Keep internal factory calls close to the validated operator code path.
When it happens
Trigger: Calling AsyncObserver.Join(observer: null, subscriptions, leftDurationSelector, rightDurationSelector, resultSelector) — normally only reachable via custom operator plumbing that passes a null downstream observer.
Common situations: Custom operator implementations or test harnesses that construct AsyncObserver.Join directly and forget to supply the downstream observer, often because an outer observer variable was never initialized.
Related errors
- Value cannot be null. (Parameter 'observer')
- observer
- throw new ArgumentNullException(nameof(observer));
- func
- observer
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/b4330993d815356f.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Join.cs:52
var (leftObserver, rightObserver, disposable) = AsyncObserver.Join(observer, subscriptions, state.leftDurationSelector, state.rightDurationSelector, state.resultSelector);
var leftSubscription = await left.SubscribeSafeAsync(leftObserver).ConfigureAwait(false);
await subscriptions.AddAsync(leftSubscription).ConfigureAwait(false);
var rightSubscription = await state.right.SubscribeSafeAsync(rightObserver).ConfigureAwait(false);
await subscriptions.AddAsync(rightSubscription).ConfigureAwait(false);
return disposable;
});
}
}
public partial class AsyncObserver
{
public static (IAsyncObserver<TLeft>, IAsyncObserver<TRight>, IAsyncDisposable) Join<TLeft, TRight, TLeftDuration, TRightDuration, TResult>(IAsyncObserver<TResult> observer, IAsyncDisposable subscriptions, Func<TLeft, IAsyncObservable<TLeftDuration>> leftDurationSelector, Func<TRight, IAsyncObservable<TRightDuration>> rightDurationSelector, Func<TLeft, TRight, TResult> resultSelector)
{
if (observer == null)
throw new ArgumentNullException(nameof(observer));
if (subscriptions == null)
throw new ArgumentNullException(nameof(subscriptions));
if (leftDurationSelector == null)
throw new ArgumentNullException(nameof(leftDurationSelector));
if (rightDurationSelector == null)
throw new ArgumentNullException(nameof(rightDurationSelector));
if (resultSelector == null)
throw new ArgumentNullException(nameof(resultSelector));
var gate = new AsyncGate();
var group = new CompositeAsyncDisposable(subscriptions);
var leftMap = new SortedDictionary<int, TLeft>();
var rightMap = new SortedDictionary<int, TRight>();
var leftDone = false;
var rightDone = false;View on GitHub (pinned to 94b5d5ab91)