dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'end')
Error message
Value cannot be null. (Parameter 'end')
What it means
Observable.FromAsyncPattern validates its begin/end delegate arguments up front and throws ArgumentNullException('end') when the end (IAsyncResult result selector) delegate is null. The APM Begin/End pattern requires both delegates to wrap an async operation into an IObservable, so a null end delegate cannot produce a valid sequence. The library throws eagerly at wrapper creation time rather than at subscription time.
Solutions
- Ensure a non-null end delegate Func<IAsyncResult, TResult> is passed as the second argument
- Check that any reflection/config lookup producing the end delegate succeeded before calling FromAsyncPattern
- Prefer the modern Task-based FromAsync pattern (Observable.FromAsync of a Func<Task<T>>) which avoids Begin/End pairs entirely
Example fix
// before var end = (Func<IAsyncResult, string>)null; var f = Observable.FromAsyncPattern<string>(begin, end); // after var end = iar => ((FileStream)iar.AsyncState).EndRead(iar) is var n ? Encoding.UTF8.GetString(n == 0 ? Array.Empty<byte>() : buffer, 0, n) : null; var f = Observable.FromAsyncPattern<string>(begin, end);
Defensive patterns
Strategy: validation
Validate before calling
if (end == null) throw new InvalidOperationException("FromAsyncPattern requires a non-null end delegate");
var f = Observable.FromAsyncPattern<TResult>(begin, end); Type guard
static bool HasBeginEnd<TArg,TResult>(Func<TArg, AsyncCallback, object?, IAsyncResult> begin, Func<IAsyncResult, TResult> end) => begin != null && end != null;
Try / catch
try
{
var f = Observable.FromAsyncPattern<TResult>(begin, end);
}
catch (ArgumentNullException ex) when (ex.ParamName == "end")
{
// supply or repair the end delegate
} Prevention
- Always pass the EndXxx method group together with its BeginXxx counterpart
- Null-check delegates resolved via reflection or configuration before wrapping
- Prefer Observable.FromAsync with Task-based APIs over obsolete FromAsyncPattern
When it happens
Trigger: Calling the parameterless Observable.FromAsyncPattern(begin, end) overload with a non-null begin delegate but a null end delegate, e.g. FromAsyncPattern(begun, null) or passing a variable that was never assigned.
Common situations: Converting legacy Stream/WebRequest BeginXxx/EndXxx pairs to Rx; the End delegate is looked up via reflection or config and the lookup returns null; refactoring removed the end method but the call site still compiles because the parameter accepts any Func.
Related errors
- end
- begin
- Value cannot be null. (Parameter 'functionAsync')
- Value cannot be null. (Parameter 'options')
- Value cannot be null. (Parameter 'resourceFactoryAsync')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/884d95ff791660c8.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.Async.cs:36
/// 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>
/// <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, IObservable<TResult>> FromAsyncPattern<TArg1, TResult>(Func<TArg1, AsyncCallback, object?, IAsyncResult> begin, Func<IAsyncResult, TResult> end)
{View on GitHub (pinned to 94b5d5ab91)