dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'onNext')
Error message
Value cannot be null. (Parameter 'onNext')
What it means
Thrown by the notification-based SelectMany(source, onNext, onError, onCompleted) overload when the onNext delegate (Func<TSource, IObservable<TResult>>) is null. Rx requires all three notification handlers because each notification kind must map to a sequence; a null onNext is rejected eagerly at call time.
Solutions
- Provide an onNext lambda projecting each element to an IObservable<TResult>, e.g. x => Observable.Return(Process(x)).
- If elements should be ignored, pass x => Observable.Empty<TResult>() instead of null.
- Use a different SelectMany overload (single selector) if no per-notification handling is required.
Example fix
// before var q = source.SelectMany(null, err => Observable.Throw<Item>(err), () => Observable.Empty<Item>()); // after var q = source.SelectMany(x => Observable.Return(Process(x)), err => Observable.Throw<Item>(err), () => Observable.Empty<Item>());
Defensive patterns
Strategy: validation
Validate before calling
if (onNext is null) throw new ArgumentNullException(nameof(onNext)); // check before invoking SelectMany
Type guard
static bool HandlersValid<TSource, TResult>(Func<TSource, IObservable<TResult>> onNext)
=> onNext is not null; Try / catch
try
{
var q = source.SelectMany(onNext, onError, onCompleted);
}
catch (ArgumentNullException ex) when (ex.ParamName == "onNext")
{
// substitute a default element mapping
q = source.SelectMany(x => Observable.Empty<TResult>(), onError, onCompleted);
} Prevention
- Do not carry the Subscribe convention (null handlers allowed) into Rx LINQ operators.
- For 'ignore elements' semantics pass x => Observable.Empty<TResult>() instead of null.
- Keep the three notification handlers grouped in a small helper so they are always supplied together.
When it happens
Trigger: Calling Observable.SelectMany(source, null, onError, onCompleted) — the element-to-observable projection is null, commonly when the onError/onCompleted handlers are supplied but the element handler was omitted by mistake.
Common situations: Confusion with Subscribe-style handlers where passing null for onNext is legal; copying the Subscribe(source, null, onError, onCompleted) pattern into SelectMany; conditional construction where only error handling was implemented so far.
Related errors
- Value cannot be null. (Parameter 'onError')
- Value cannot be null. (Parameter 'onCompleted')
- Value cannot be null. (Parameter 'func')
- Value cannot be null. (Parameter 'resultSelector')
- new ArgumentNullException(nameof(comparer))
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/14fbd4b488bc3c18.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.StandardSequenceOperators.cs:1380
/// </summary>
/// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
/// <typeparam name="TResult">The type of the elements in the projected inner sequences and the elements in the merged result sequence.</typeparam>
/// <param name="source">An observable sequence of notifications to project.</param>
/// <param name="onNext">A transform function to apply to each element.</param>
/// <param name="onError">A transform function to apply when an error occurs in the source sequence.</param>
/// <param name="onCompleted">A transform function to apply when the end of the source sequence is reached.</param>
/// <returns>An observable sequence whose elements are the result of invoking the one-to-many transform function corresponding to each notification in the input sequence.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="onNext"/> or <paramref name="onError"/> or <paramref name="onCompleted"/> is null.</exception>
public static IObservable<TResult> SelectMany<TSource, TResult>(this IObservable<TSource> source, Func<TSource, IObservable<TResult>> onNext, Func<Exception, IObservable<TResult>> onError, Func<IObservable<TResult>> onCompleted)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (onNext == null)
{
throw new ArgumentNullException(nameof(onNext));
}
if (onError == null)
{
throw new ArgumentNullException(nameof(onError));
}
if (onCompleted == null)
{
throw new ArgumentNullException(nameof(onCompleted));
}
return s_impl.SelectMany(source, onNext, onError, onCompleted);
}
/// <summary>
/// Projects each notification of an observable sequence to an observable sequence by incorporating the element's index and merges the resulting observable sequences into one observable sequence.
/// </summary>View on GitHub (pinned to 94b5d5ab91)