dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'windowClosingSelector')

Error message

Value cannot be null. (Parameter 'windowClosingSelector')

What it means

This ArgumentNullException is thrown by the Window<TSource,TWindowClosing> operator when the windowClosingSelector delegate is null. The selector is required to create each new window's closing observable, so the operator rejects a null selector immediately at call time. No subscription ever happens in this case.

Solutions

  1. Pass a non-null window-closing selector, e.g. () => AsyncObservable.Interval(TimeSpan.FromSeconds(5)).
  2. If the selector comes from a variable, initialize it before calling Window.
  3. Throw your own descriptive exception at the call site if the selector may legitimately be absent.
  4. Choose a different Window overload (count-based or time-based) if a closing selector isn't actually needed.

Example fix

// before
Func<IAsyncObservable<long>> closing = null;
var windows = source.Window(closing);
// after
var windows = source.Window(() => AsyncObservable.Interval(TimeSpan.FromSeconds(5)));
Defensive patterns

Strategy: validation

Validate before calling

if (windowClosingSelector is null) throw new ArgumentNullException(nameof(windowClosingSelector));

Type guard

bool IsValidSelector<TW>(Func<IAsyncObservable<TW>>? sel) => sel is not null;

Try / catch

try
{
    var windows = source.Window(closingSelector);
}
catch (ArgumentNullException ex) when (ex.ParamName == "windowClosingSelector")
{
    closingSelector = () => AsyncObservable.Interval(TimeSpan.FromSeconds(5));
}

Prevention

When it happens

Trigger: Calling source.Window(null) on the parameterless overload, e.g. a Func<IAsyncObservable<TWindowClosing>> variable that was never assigned, or a conditional expression that resolved to null.

Common situations: Passing a method group that doesn't match an overload and binding to null instead; storing the selector in a nullable field initialized after use; refactoring that removed the lambda but left the call.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Window.cs:169

                    var sourceSubscription = await source.SubscribeSafeAsync(sourceObserver).ConfigureAwait(false);
                    await d.AddAsync(sourceSubscription).ConfigureAwait(false);

                    var boundariesSubscription = await windowBoundaries.SubscribeSafeAsync(boundariesObserver).ConfigureAwait(false);
                    await d.AddAsync(boundariesSubscription).ConfigureAwait(false);

                    return subscription;
                });
        }

        // REVIEW: This overload is inherited from Rx but arguably a bit esoteric as it doesn't provide context to the closing selector.

        public static IAsyncObservable<IAsyncObservable<TSource>> Window<TSource, TWindowClosing>(this IAsyncObservable<TSource> source, Func<IAsyncObservable<TWindowClosing>> windowClosingSelector)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (windowClosingSelector == null)
                throw new ArgumentNullException(nameof(windowClosingSelector));

            return CreateAsyncObservable<IAsyncObservable<TSource>>.From(
                source,
                windowClosingSelector,
                static async (source, windowClosingSelector, observer) =>
                {
                    var d = new CompositeAsyncDisposable();

                    var (sourceObserver, closingSubscription, subscription) = await AsyncObserver.Window<TSource, TWindowClosing>(observer, windowClosingSelector, d).ConfigureAwait(false);

                    await d.AddAsync(closingSubscription).ConfigureAwait(false);

                    var sourceSubscription = await source.SubscribeSafeAsync(sourceObserver).ConfigureAwait(false);
                    await d.AddAsync(sourceSubscription).ConfigureAwait(false);

                    return subscription;
                });
        }

View on GitHub (pinned to 94b5d5ab91)