dotnet/reactive · error · ArgumentNullException

source (Parameter 'source')

Error message

source (Parameter 'source')

What it means

The ToObservable(this IAsyncAction source) extension converts a WinRT IAsyncAction into an IObservable<Unit> that completes when the async action completes; it throws ArgumentNullException when 'source' is null. Rx needs the actual WinRT async object to attach its AsyncActionCompletedHandler, so a null source cannot be bridged.

Solutions

  1. Ensure the IAsyncAction is non-null before calling ToObservable; fix the producing method to always return a valid action.
  2. Guard the call: if (source != null) { ... ToObservable() ... } else return Observable.Empty<Unit>();
  3. If the producer may return null by design, wrap it in Observable.Defer and check inside.

Example fix

// before
IAsyncAction action = GetAction(); // may be null
var obs = action.ToObservable();
// after
var obs = GetAction() is IAsyncAction action
    ? action.ToObservable()
    : Observable.Empty<Unit>();
Defensive patterns

Strategy: validation

Validate before calling

// csharp
if (source == null)
    return Observable.Empty<Unit>();
var obs = source.ToObservable();

Type guard

// csharp
bool IsBridgable(IAsyncAction source) => source is not null;

Try / catch

// csharp
try { obs = source.ToObservable(); }
catch (ArgumentNullException ex) when (ex.ParamName == "source") { obs = Observable.Throw<Unit>(new InvalidOperationException("Async action was null")); }

Prevention

When it happens

Trigger: Calling source.ToObservable() where source is a null IAsyncAction reference — e.g. a method returning IAsyncAction returned null, or a WinRT API returned a null result.

Common situations: Interoping with WinRT APIs that can return null async operations; calling the extension on the result of a factory that failed silently; storing the async action in a nullable field not yet assigned.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Platforms/WinRT/Foundation/AsyncInfoExtensions.cs:30

    /// Provides conversions from Windows Runtime asynchronous actions and operations to observable sequences.
    /// </summary>
    [CLSCompliant(false)]
    public static class AsyncInfoObservableExtensions
    {
        #region IAsyncAction and IAsyncActionWithProgress

        /// <summary>
        /// Converts a Windows Runtime asynchronous action to an observable sequence.
        /// Each observer subscribed to the resulting observable sequence will be notified about the action's successful or exceptional completion.
        /// </summary>
        /// <param name="source">Asynchronous action to convert.</param>
        /// <returns>An observable sequence that produces a unit value when the asynchronous action completes, or propagates the exception produced by the asynchronous action.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
        public static IObservable<Unit> ToObservable(this IAsyncAction source)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            return new AsyncInfoToObservableBridge<Unit, Unit>(
                source,
                static (iai, a) => ((IAsyncAction)iai).Completed += new AsyncActionCompletedHandler((iaa, status) => a(iaa, status)),
                iai => Unit.Default,
                onProgress: null,
                progress: null,
                multiValue: false
            );
        }

        /// <summary>
        /// Converts a Windows Runtime asynchronous action to an observable sequence, ignoring its progress notifications.
        /// Each observer subscribed to the resulting observable sequence will be notified about the action's successful or exceptional completion.
        /// </summary>
        /// <typeparam name="TProgress">The type of the reported progress objects, which get ignored by this conversion.</typeparam>
        /// <param name="source">Asynchronous action to convert.</param>

View on GitHub (pinned to 94b5d5ab91)