dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'source')

Error message

Value cannot be null. (Parameter 'source')

What it means

The parameterless Replay() extension requires a non-null source IAsyncObservable. It validates arguments up front and throws ArgumentNullException before creating the SequentialReplayAsyncSubject / connectable wrapper. This is a programming error in the caller, not a runtime condition.

Solutions

  1. Ensure the source observable is created before calling Replay (check the factory method for null-returning paths).
  2. Coalesce to an empty observable if a null source is legitimate: source ?? AsyncObservable.Empty<T>().
  3. Throw early in your own factory if the source cannot be built, so failures surface at creation time.

Example fix

// before
var src = cache.Get(key); // may be null
var replay = src.Replay();
// after
var src = cache.Get(key) ?? AsyncObservable.Empty<int>();
var replay = src.Replay();
Defensive patterns

Strategy: validation

Validate before calling

if (source == null)
    throw new InvalidOperationException("Source observable must be created before calling Replay.");
var replay = source.Replay();

Type guard

static bool IsNonNull<T>(IAsyncObservable<T> source) => source is not null;

Try / catch

try
{
    var replay = source.Replay();
}
catch (ArgumentNullException ex) when (ex.ParamName == "source")
{
    // log and fall back to building the source again
}

Prevention

When it happens

Trigger: Calling source.Replay() where source is null — typically the result of a factory/lookup that returned null, or chaining off a nullable expression.

Common situations: A GetObservable-style helper returning null on cache miss; conditional pipeline construction where an earlier step was skipped; refactoring that removed null-coalescing around the source.

Related errors


AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15). Data as JSON: /api/errors/7bec09515f7c97c5. Report an issue: GitHub.

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Replay.cs:18

// 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.Concurrency;
using System.Reactive.Subjects;
using System.Threading.Tasks;

namespace System.Reactive.Linq
{
    // REVIEW: Expose Replay using ConcurrentAsyncAsyncSubject<T> underneath.

    public partial class AsyncObservable
    {
        public static IConnectableAsyncObservable<TSource> Replay<TSource>(this IAsyncObservable<TSource> source)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));

            return Multicast(source, new SequentialReplayAsyncSubject<TSource>());
        }

        public static IConnectableAsyncObservable<TSource> Replay<TSource>(this IAsyncObservable<TSource> source, IAsyncScheduler scheduler)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (scheduler == null)
                throw new ArgumentNullException(nameof(scheduler));

            return Multicast(source, new SequentialReplayAsyncSubject<TSource>(scheduler));
        }

        public static IConnectableAsyncObservable<TSource> Replay<TSource>(this IAsyncObservable<TSource> source, int bufferSize)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));

View on GitHub (pinned to 94b5d5ab91)