dotnet/reactive · error · ArgumentNullException
throw new ArgumentNullException(nameof(scheduler))
Error message
throw new ArgumentNullException(nameof(scheduler))
What it means
The scheduler overload Expand(source, selector, scheduler) requires an IScheduler to time recursive expansions; a null scheduler throws ArgumentNullException named 'scheduler'. Rx requires an explicit scheduler here because Expand's recursion depends on scheduling semantics that cannot be defaulted inside a queryable expression tree.
Solutions
- Pass a concrete scheduler such as Scheduler.Default, Scheduler.CurrentThread, or Scheduler.Immediate
- Resolve IScheduler from DI and assert non-null before composing the query
- Provide an overload without a scheduler if scheduling is genuinely optional
Example fix
// before source.Expand(x => Observable.Return(x), scheduler); // scheduler is null // after var scheduler = configuredScheduler ?? Scheduler.Default; source.Expand(x => Observable.Return(x), scheduler);
Defensive patterns
Strategy: validation
Validate before calling
if (scheduler == null)
throw new InvalidOperationException("Expand requires an IScheduler; use Scheduler.Default"); Type guard
bool HasScheduler(IScheduler s) => s is not null;
Try / catch
try
{
var query = source.Expand(x => Observable.Return(x), scheduler);
}
catch (ArgumentNullException ex) when (ex.ParamName == "scheduler")
{
logger.LogError(ex, "Expand scheduler was null");
} Prevention
- Coalesce configured schedulers with Scheduler.Default at pipeline setup
- Register IScheduler in DI and validate at startup
- Never pass null to mean 'default' — use the no-scheduler overload instead
When it happens
Trigger: Calling source.Expand(selector, null) — scheduler from a null configuration value, a TestScheduler variable not yet created, or an IScheduler dependency that failed to resolve.
Common situations: DI failing to provide IScheduler; config where the scheduler name wasn't mapped; passing null deliberately in unit tests to mean 'default' instead of using Scheduler.Default.
Related errors
- nameof(scheduler)
- nameof(scheduler)
- throw new ArgumentNullException(nameof(selector))
- throw new ArgumentNullException(nameof(source))
- Value cannot be null. (Parameter 'action')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/958307dea7f092b8.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Linq/QbservableEx.Homoicon.cs:1057
/// <summary>
/// Expands an observable sequence by recursively invoking selector, using the specified scheduler to enumerate the queue of obtained sequences.
/// </summary>
/// <typeparam name="TSource">The type of the elements in the source sequence and each of the recursively expanded sources obtained by running the selector function.</typeparam>
/// <param name="source">Source sequence with the initial elements.</param>
/// <param name="selector">Selector function to invoke for each produced element, resulting in another sequence to which the selector will be invoked recursively again.</param>
/// <param name="scheduler">Scheduler on which to perform the expansion by enumerating the internal queue of obtained sequences.</param>
/// <returns>An observable sequence containing all the elements produced by the recursive expansion.</returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="source" /> or <paramref name="selector" /> or <paramref name="scheduler" /> is null.</exception>
[Experimental]
public static IQbservable<TSource> Expand<TSource>(this IQbservable<TSource> source, Expression<Func<TSource, IObservable<TSource>>> selector, IScheduler scheduler)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (selector == null)
throw new ArgumentNullException(nameof(selector));
if (scheduler == null)
throw new ArgumentNullException(nameof(scheduler));
return source.Provider.CreateQuery<TSource>(
Expression.Call(
null,
new Func<IQbservable<TSource>, Expression<Func<TSource, IObservable<TSource>>>, IScheduler, IQbservable<TSource>>(Expand<TSource>).Method,
source.Expression,
selector,
Expression.Constant(scheduler, typeof(IScheduler))
)
);
}
#endif
#if !STABLE
/// <summary>
/// Runs all specified observable sequences in parallel and collects their last elements.
/// </summary>
/// <param name="provider">Query provider used to construct the <see cref="IQbservable{T}"/> data source.</param>View on GitHub (pinned to 94b5d5ab91)