dotnet/reactive · error · ArgumentNullException

begin

Error message

begin

What it means

The two-argument FromAsyncPattern<TArg1,TArg2,TResult> overload throws ArgumentNullException('begin') when the Func<TArg1,TArg2,AsyncCallback,object?,IAsyncResult> begin delegate is null. The begin delegate starts the asynchronous operation for each invocation of the resulting function; it is required and checked eagerly. This APM-based overload family is also marked obsolete in favor of the Task-based API.

Solutions

  1. Provide a non-null begin delegate invoking the underlying BeginXxx method with both arguments
  2. Assert delegate non-nullness before calling FromAsyncPattern
  3. Replace with Observable.FromAsync((a,b) => Task-returning method)

Example fix

// before
var f = Observable.FromAsyncPattern<string, int, byte[]>(null, end);
// after
var f = Observable.FromAsyncPattern<string, int, byte[]>(
    (path, off, cb, st) => fs.BeginRead(buffer, off, size, cb, st),
    iar => fs.EndRead(iar));
Defensive patterns

Strategy: validation

Validate before calling

if (begin == null) throw new InvalidOperationException("begin delegate must be provided");
var f = Observable.FromAsyncPattern<TArg1, TArg2, TResult>(begin, end);

Type guard

static bool HasBegin<TArg1,TArg2,TResult>(Func<TArg1, TArg2, AsyncCallback, object?, IAsyncResult> begin) => begin != null;

Try / catch

try
{
    var f = Observable.FromAsyncPattern<TArg1, TArg2, TResult>(begin, end);
}
catch (ArgumentNullException ex) when (ex.ParamName == "begin")
{
    // repair the begin delegate
}

Prevention

When it happens

Trigger: Observable.FromAsyncPattern<TArg1,TArg2,TResult>(null, end) with two arguments and a valid end delegate.

Common situations: Reflection-based delegate construction failing silently; refactoring that removed a BeginXxx wrapper; passing a method group whose overload resolution failed and produced null in dynamic code.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.Async.cs:84

        }

        /// <summary>
        /// Converts a Begin/End invoke function pair into an asynchronous function.
        /// </summary>
        /// <typeparam name="TArg1">The type of the first argument passed to the begin delegate.</typeparam>
        /// <typeparam name="TArg2">The type of the second argument passed to the begin delegate.</typeparam>
        /// <typeparam name="TResult">The type of the result returned by the end delegate.</typeparam>
        /// <param name="begin">The delegate that begins the asynchronous operation.</param>
        /// <param name="end">The delegate that ends the asynchronous operation.</param>
        /// <returns>Function that can be used to start the asynchronous operation and retrieve the result as an observable sequence.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="begin"/> or <paramref name="end"/> is null.</exception>
        /// <remarks>Each invocation of the resulting function will cause the asynchronous operation to be started. Subscription to the resulting sequence has no observable side-effect, and each subscription will produce the asynchronous operation's result.</remarks>
        [Obsolete(Constants_Linq.UseTaskFromAsyncPattern)]
        public static Func<TArg1, TArg2, IObservable<TResult>> FromAsyncPattern<TArg1, TArg2, TResult>(Func<TArg1, TArg2, AsyncCallback, object?, IAsyncResult> begin, Func<IAsyncResult, TResult> end)
        {
            if (begin == null)
            {
                throw new ArgumentNullException(nameof(begin));
            }

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

            return s_impl.FromAsyncPattern(begin, end);
        }

        /// <summary>
        /// Converts a Begin/End invoke function pair into an asynchronous function.
        /// </summary>
        /// <typeparam name="TArg1">The type of the first argument passed to the begin delegate.</typeparam>
        /// <typeparam name="TArg2">The type of the second argument passed to the begin delegate.</typeparam>
        /// <typeparam name="TArg3">The type of the third argument passed to the begin delegate.</typeparam>
        /// <typeparam name="TResult">The type of the result returned by the end delegate.</typeparam>
        /// <param name="begin">The delegate that begins the asynchronous operation.</param>

View on GitHub (pinned to 94b5d5ab91)