dotnet/reactive · error · ArgumentNullException

selector

Error message

selector

What it means

The Replay(source, selector, bufferSize, scheduler) overload throws ArgumentNullException because the selector delegate passed was null. The operator needs a non-null selector to build the multicast pipeline over the replay subject; a null selector would make the returned observable impossible to construct. The library validates all arguments eagerly at call time so failures surface at the call site rather than later during subscription.

Solutions

  1. Pass a non-null selector lambda, e.g. src => src.Select(...).Where(...).
  2. If the selector is variable, check it for null before calling Replay and handle the fallback explicitly.
  3. Verify the variable actually holds the composed delegate and was not reassigned to null elsewhere.

Example fix

// before
IAsyncObservable<int> result = source.Replay(null, 10, Scheduler.Default.Async);
// after
IAsyncObservable<int> result = source.Replay(xs => xs.Select(x => x * 2), 10, Scheduler.Default.Async);
Defensive patterns

Strategy: validation

Validate before calling

if (selector is null) throw new InvalidOperationException("Replay selector must be provided");
// safe to call source.Replay(selector, bufferSize, scheduler);

Type guard

bool HasSelector(Func<IAsyncObservable<TSource>, IAsyncObservable<TResult>> f) => f is not null;

Try / catch

try { var r = source.Replay(selector, bufferSize, scheduler); }
catch (ArgumentNullException ex) when (ex.ParamName == "selector") { /* supply a default selector or fail fast */ }

Prevention

When it happens

Trigger: Calling source.Replay(null, bufferSize, scheduler) or passing a variable/ternary/expression that evaluates to a null Func<IAsyncObservable<TSource>, IAsyncObservable<TResult>>.

Common situations: Building the selector dynamically (e.g. from configuration or a dictionary of transforms) and the lookup fails returning null; refactoring code where the selector lambda was accidentally deleted; conditional pipelines that pass null when a feature flag is off.

Related errors


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

Appendix: source

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

        public static IAsyncObservable<TResult> Replay<TSource, TResult>(this IAsyncObservable<TSource> source, Func<IAsyncObservable<TSource>, IAsyncObservable<TResult>> selector, int bufferSize)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (selector == null)
                throw new ArgumentNullException(nameof(selector));
            if (bufferSize < 0)
                throw new ArgumentOutOfRangeException(nameof(bufferSize));

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

        public static IAsyncObservable<TResult> Replay<TSource, TResult>(this IAsyncObservable<TSource> source, Func<IAsyncObservable<TSource>, IAsyncObservable<TResult>> selector, int bufferSize, IAsyncScheduler scheduler)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (selector == null)
                throw new ArgumentNullException(nameof(selector));
            if (bufferSize < 0)
                throw new ArgumentOutOfRangeException(nameof(bufferSize));
            if (scheduler == null)
                throw new ArgumentNullException(nameof(scheduler));

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

        public static IAsyncObservable<TResult> Replay<TSource, TResult>(this IAsyncObservable<TSource> source, Func<IAsyncObservable<TSource>, IAsyncObservable<TResult>> selector, TimeSpan window)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (selector == null)
                throw new ArgumentNullException(nameof(selector));
            if (window < TimeSpan.Zero)
                throw new ArgumentOutOfRangeException(nameof(window));

            return Multicast(source, () => new SequentialReplayAsyncSubject<TSource>(window), selector);

View on GitHub (pinned to 94b5d5ab91)