dotnet/reactive · error · ArgumentNullException

ArgumentNullException: progressSelector

Error message

ArgumentNullException: progressSelector

What it means

In the same ToAsyncActionWithProgress overload, after source is validated, a null progressSelector (Func<IObservable<TSource>, IObservable<TProgress>>) throws ArgumentNullException('progressSelector'). The selector is required to compute progress notifications from the source sequence.

Solutions

  1. Pass a valid Func<IObservable<TSource>, IObservable<TProgress>>.
  2. Null-check or default the selector before calling (e.g. src => Observable.Return(100)).
  3. Fix argument order if null is landing in the selector slot by mistake.

Example fix

// before
source.ToAsyncActionWithProgress(progressSelector); // progressSelector == null
// after
var sel = progressSelector ?? (src => Observable.Return(100));
source.ToAsyncActionWithProgress(sel);
Defensive patterns

Strategy: validation

Validate before calling

if (progressSelector is null)
    progressSelector = src => Observable.Return(100); // or throw with clear message

Type guard

bool HasSelector<TSource,TProgress>(Func<IObservable<TSource>, IObservable<TProgress>>? sel) => sel is not null;

Try / catch

try { var a = source.ToAsyncActionWithProgress(progressSelector); }
catch (ArgumentNullException ex) when (ex.ParamName == "progressSelector") { /* supply selector */ }

Prevention

When it happens

Trigger: Calling source.ToAsyncActionWithProgress(null) or passing a selector variable/expression that evaluates to null.

Common situations: Optional selector parameters forwarded as-is, conditional selector construction returning null, 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/bea4260bd951ecad. Report an issue: GitHub.

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive.WindowsRuntime/System.Reactive.Linq/AsyncInfoObservable.cs:88

        /// Creates a Windows Runtime asynchronous action that represents the completion of the observable sequence, using a selector function to map the source sequence on a progress reporting sequence.
        /// Upon cancellation of the asynchronous action, the subscription to the source sequence will be disposed.
        /// </summary>
        /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
        /// <typeparam name="TProgress">The type of the elements in the progress sequence.</typeparam>
        /// <param name="source">Source sequence to expose as an asynchronous action and to compute a progress sequence that gets reported through the asynchronous action.</param>
        /// <param name="progressSelector">Selector function to map the source sequence on a progress reporting sequence.</param>
        /// <returns>Windows Runtime asynchronous action object representing the completion of the result sequence, reporting progress computed through the progress sequence.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="progressSelector"/> is null.</exception>
        public static IAsyncActionWithProgress<TProgress> ToAsyncActionWithProgress<TSource, TProgress>(this IObservable<TSource> source, Func<IObservable<TSource>, IObservable<TProgress>> progressSelector)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            if (progressSelector == null)
            {
                throw new ArgumentNullException(nameof(progressSelector));
            }

            return AsyncInfo.Run<TProgress>((ct, progress) =>
            {
                return Observable.Create<TSource?>(observer =>
                {
                    var obs = Observer.Synchronize(observer);

                    var data = source.Publish();

                    var progressSubscription = progressSelector(data).Subscribe(progress.Report, obs.OnError);
                    var dataSubscription = data.DefaultIfEmpty().Subscribe(obs);
                    var connection = data.Connect();

                    return StableUncheckedCompositeDisposable.CreateTrusted(progressSubscription, dataSubscription, connection);
                }).ToTask(ct);
            });
        }

View on GitHub (pinned to 94b5d5ab91)