dotnet/reactive · error · ArgumentNullException

throw new ArgumentNullException(nameof(throttleSelector));

Error message

throw new ArgumentNullException(nameof(throttleSelector));

What it means

In the selector-based Throttle overload, the throttleSelector function produces the per-item throttle duration sequence. It is essential to the operator's behavior, so a null selector is rejected up front with ArgumentNullException.

Solutions

  1. Pass a non-null lambda, e.g. source.Throttle(x => AsyncObservable.Timer(dueTimeFor(x)))
  2. Initialize or register the delegate before use
  3. Guard the call site: if (selector != null) ... else use the TimeSpan overload

Example fix

// before
Func<int, IAsyncObservable<long>> sel = lookup["throttle"] as Func<int, IAsyncObservable<long>>; // null if missing
var throttled = source.Throttle(sel);
// after
var throttled = source.Throttle(x => AsyncObservable.Timer(TimeSpan.FromMilliseconds(x)));
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

static bool IsValidSelector<TSource,TThrottle>(Func<TSource, IAsyncObservable<TThrottle>> f) => f is not null;

Try / catch

try { var t = source.Throttle(selector); }
catch (ArgumentNullException ex) when (ex.ParamName == "throttleSelector") { /* substitute default selector */ }

Prevention

When it happens

Trigger: Calling source.Throttle((Func<TSource, IAsyncObservable<TThrottle>>)null), e.g. passing a selector variable that was never assigned or a conditional expression that evaluated to null.

Common situations: Building the selector dynamically (reflection, dictionary of delegates) and the lookup missed; a class member Func field is null until initialized; method-group binding failed and returned null via reflection.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Throttle.cs:72

                    var (sink, throttler) = AsyncObserver.Throttle(observer, state.dueTime, state.scheduler);

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

                    var sourceSubscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false);

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

                    return d;
                });
        }

        public static IAsyncObservable<TSource> Throttle<TSource, TThrottle>(this IAsyncObservable<TSource> source, Func<TSource, IAsyncObservable<TThrottle>> throttleSelector)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (throttleSelector == null)
                throw new ArgumentNullException(nameof(throttleSelector));

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

                    var (sink, throttler) = AsyncObserver.Throttle(observer, throttleSelector);

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

                    var sourceSubscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false);

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

                    return d;
                });

View on GitHub (pinned to 94b5d5ab91)