dotnet/reactive · error · ArgumentNullException
ArgumentNullException(nameof(scheduler))
Error message
ArgumentNullException(nameof(scheduler))
What it means
The Merge(IEnumerable<IObservable<TSource>>, int, IScheduler) overload throws ArgumentNullException when the scheduler argument is null. Rx requires an explicit IScheduler for this overload because scheduling governs how concurrent subscriptions are orchestrated.
Solutions
- Pass a concrete scheduler such as Scheduler.Default, TaskPoolScheduler.Default, or CurrentThreadScheduler.Default.
- If injection is used, verify the IScheduler registration in the DI container.
- Coalesce with Scheduler.Default at the call site if a null scheduler is acceptable to treat as default.
- Check initialization order so the scheduler field is assigned before Merge runs.
Example fix
// before var merged = sources.Merge(4, _scheduler); // _scheduler is null // after var merged = sources.Merge(4, _scheduler ?? Scheduler.Default);
Defensive patterns
Strategy: validation
Validate before calling
if (scheduler is null) scheduler = Scheduler.Default;
Type guard
static bool HasScheduler(IScheduler s) => s is not null;
Try / catch
try { var merged = sources.Merge(4, scheduler); }
catch (ArgumentNullException ex) when (ex.ParamName == "scheduler")
{
var merged = sources.Merge(4, Scheduler.Default);
} Prevention
- Register IScheduler in your DI container so it can never resolve to null.
- Default scheduler fields to Scheduler.Default at declaration.
- Check initialization order in constructors and tests.
- Avoid nullable scheduler parameters; require a scheduler explicitly.
When it happens
Trigger: Calling Merge(sources, maxConcurrent, scheduler) where scheduler is null — commonly a field not yet assigned, a factory that returned null, or passing a dependency that was never injected.
Common situations: DI container misconfiguration where IScheduler was not registered; using a scheduler variable before initialization in tests; migrating code that removed Scheduler.Default.
Related errors
- action (Parameter 'action')
- action (Parameter 'action')
- comparer (Parameter 'comparer')
- scheduler (Parameter 'scheduler')
- scheduler (Parameter 'scheduler')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/aaa88c86cbb420d5.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.Multiple.cs:548
/// <param name="scheduler">Scheduler to run the enumeration of the sequence of sources on.</param>
/// <returns>The observable sequence that merges the elements of the observable sequences.</returns>
/// <exception cref="ArgumentNullException"><paramref name="sources"/> or <paramref name="scheduler"/> is null.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="maxConcurrent"/> is less than or equal to zero.</exception>
public static IObservable<TSource> Merge<TSource>(this IEnumerable<IObservable<TSource>> sources, int maxConcurrent, IScheduler scheduler)
{
if (sources == null)
{
throw new ArgumentNullException(nameof(sources));
}
if (maxConcurrent <= 0)
{
throw new ArgumentOutOfRangeException(nameof(maxConcurrent));
}
if (scheduler == null)
{
throw new ArgumentNullException(nameof(scheduler));
}
return s_impl.Merge(sources, maxConcurrent, scheduler);
}
/// <summary>
/// Merges elements from two observable sequences into a single observable sequence.
/// </summary>
/// <typeparam name="TSource">The type of the elements in the source sequences.</typeparam>
/// <param name="first">First observable sequence.</param>
/// <param name="second">Second observable sequence.</param>
/// <returns>The observable sequence that merges the elements of the given sequences.</returns>
/// <exception cref="ArgumentNullException"><paramref name="first"/> or <paramref name="second"/> is null.</exception>
public static IObservable<TSource> Merge<TSource>(this IObservable<TSource> first, IObservable<TSource> second)
{
if (first == null)
{
throw new ArgumentNullException(nameof(first));View on GitHub (pinned to 94b5d5ab91)