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

  1. Provide a non-null source observable; verify the factory/method producing it never returns null.
  2. Substitute Observable.Empty<TSource>() when there is genuinely no source.
  3. 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

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


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)