dotnet/reactive · error · ArgumentNullException
source
Error message
source
What it means
The two-parameter Multicast(source, subject) overload throws ArgumentNullException with param name "source" when the input IObservable<TSource> is null. Rx.NET validates every public operator argument up front so failures happen deterministically at call time, not at Subscribe/Connect time. Multicasting requires a real source sequence to push notifications into the subject.
Solutions
- Provide a non-null source observable; verify the factory/method producing it never returns null.
- Substitute Observable.Empty<TSource>() when there is genuinely no source.
- Add a null check or ?? Observable.Empty<TSource>() fallback before calling Multicast.
Example fix
// before var connectable = maybeSource.Multicast(subject); // after var connectable = (maybeSource ?? Observable.Empty<int>()).Multicast(subject);
Defensive patterns
Strategy: validation
Validate before calling
if (source is null || subject is null) throw new ArgumentException("source and subject must be non-null");
var connectable = source.Multicast(subject); Type guard
static bool CanMulticast<TSource, TResult>(IObservable<TSource>? s, ISubject<TSource, TResult>? sub) => s is not null && sub is not null;
Try / catch
try { connectable = source.Multicast(subject); }
catch (ArgumentNullException ex) when (ex.ParamName == "source") { connectable = Observable.Empty<TResult>().Multicast(subject); } Prevention
- Centralize observable creation so null can never leak into operator chains.
- Use '?? Observable.Empty<T>()' defaults when wiring optional streams.
- Cover null-source paths in unit tests.
When it happens
Trigger: Calling source.Multicast(subject) where the IObservable<TSource> argument is null — e.g. the result of a repository/service method that returned null instead of an observable, or a field that was never assigned.
Common situations: Service layers that return null observables on error paths; optional dependency injection where the observable was not registered; refactoring that removed a Publish/FromEvent chain but left the variable in place.
Related errors
- subject
- subjectSelector
- Value cannot be null. (Parameter 'selector')
- keySelector
- Value cannot be null. (Parameter 'keySelector')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/dfe6f8af5480c90a.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.Binding.cs:29
{
#region + Multicast +
/// <summary>
/// Multicasts the source sequence notifications through the specified subject to the resulting connectable observable. Upon connection of the
/// connectable observable, the subject is subscribed to the source exactly one, and messages are forwarded to the observers registered with
/// the connectable observable. For specializations with fixed subject types, see Publish, PublishLast, and Replay.
/// </summary>
/// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
/// <typeparam name="TResult">The type of the elements in the result sequence.</typeparam>
/// <param name="source">Source sequence whose elements will be pushed into the specified subject.</param>
/// <param name="subject">Subject to push source elements into.</param>
/// <returns>A connectable observable sequence that upon connection causes the source sequence to push results into the specified subject.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="subject"/> is null.</exception>
public static IConnectableObservable<TResult> Multicast<TSource, TResult>(this IObservable<TSource> source, ISubject<TSource, TResult> subject)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (subject == null)
{
throw new ArgumentNullException(nameof(subject));
}
return s_impl.Multicast(source, subject);
}
/// <summary>
/// Multicasts the source sequence notifications through an instantiated subject into all uses of the sequence within a selector function. Each
/// subscription to the resulting sequence causes a separate multicast invocation, exposing the sequence resulting from the selector function's
/// invocation. For specializations with fixed subject types, see Publish, PublishLast, and Replay.
/// </summary>
/// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
/// <typeparam name="TIntermediate">The type of the elements produced by the intermediate subject.</typeparam>
/// <typeparam name="TResult">The type of the elements in the result sequence.</typeparam>View on GitHub (pinned to 94b5d5ab91)