dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'begin')

Error message

Value cannot be null. (Parameter 'begin')

What it means

Observable.FromAsyncPattern<TResult> (the legacy Begin/End APM wrapper, marked obsolete in favor of Task-based APIs) eagerly validates the begin delegate and throws ArgumentNullException when it is null. The check runs when the wrapper function is created, before it is invoked or subscribed to.

Solutions

  1. Pass valid begin/end delegates, e.g. Observable.FromAsyncPattern(stream.BeginRead, stream.EndRead).
  2. Prefer the modern alternative: use Observable.FromTask/ToObservable with Task-based APIs (TaskFactory.FromAsync or native *Async methods) instead of the obsolete FromAsyncPattern.
  3. If delegates are resolved dynamically, null-check the MethodInfo/delegate result before calling the factory.

Example fix

// before
var read = Observable.FromAsyncPattern<byte[]>(beginMethod, endMethod); // beginMethod == null
// after
var read = Observable.FromAsyncPattern<byte[]>(stream.BeginRead, stream.EndRead);
// or prefer task-based:
var read = () => Observable.FromTask(stream.ReadAsync(buffer, offset, count));
Defensive patterns

Strategy: validation

Validate before calling

if (begin == null || end == null)
    throw new ArgumentNullException(nameof(begin), "FromAsyncPattern requires non-null begin/end delegates");
var read = begin != null && end != null ? Observable.FromAsyncPattern(begin, end) : null;

Type guard

bool HasApmPair(Func<AsyncCallback, object?, IAsyncResult>? begin, Func<IAsyncResult, TResult>? end)
    => begin != null && end != null;

Try / catch

try { var op = Observable.FromAsyncPattern(begin, end); }
catch (ArgumentNullException ex) when (ex.ParamName == "begin") { /* repair Begin-method reference */ }

Prevention

When it happens

Trigger: Calling Observable.FromAsyncPattern(begin, end) with a null begin delegate — e.g. a BeginXxx method reference obtained via reflection that failed, or an uninitialized delegate variable, while end may also be null (its check follows).

Common situations: Migrating legacy APM code where Begin/End pairs are wired dynamically; reflection-based method lookup returning null when the method name/signature changed across framework versions; obsolete-API usage that was only partially ported.

Related errors


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

Appendix: source

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

        #region FromAsyncPattern

        #region Func

        /// <summary>
        /// Converts a Begin/End invoke function pair into an asynchronous function.
        /// </summary>
        /// <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<IObservable<TResult>> FromAsyncPattern<TResult>(Func<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="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>

View on GitHub (pinned to 94b5d5ab91)