dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'loopScheduler')
Error message
Value cannot be null. (Parameter 'loopScheduler')
What it means
TakeLast(source, duration, timerScheduler, loopScheduler) throws ArgumentNullException when loopScheduler is null. The loop scheduler is used to run the buffering/concurrency loop of the operator and must be provided in this overload. Validation happens immediately at the call site.
Solutions
- Pass a non-null loop scheduler (e.g. Scheduler.Default or ImmediateScheduler.Instance)
- Register/initialize the loop scheduler in your DI container or test setup
- Use the TakeLast(source, duration) overload that defaults both schedulers
Example fix
// before var res = source.TakeLast(TimeSpan.FromSeconds(5), timerScheduler, null); // after var res = source.TakeLast(TimeSpan.FromSeconds(5), timerScheduler, Scheduler.Default);
Defensive patterns
Strategy: validation
Validate before calling
if (loopScheduler == null) throw new ArgumentNullException(nameof(loopScheduler));
Type guard
bool HasLoopScheduler(IScheduler s) => s is not null;
Try / catch
try { var res = source.TakeLast(dur, timer, loop); }
catch (ArgumentNullException ex) when (ex.ParamName == "loopScheduler") { /* supply default scheduler */ } Prevention
- Pass Scheduler.Default for the loop scheduler unless a specific one is required
- Register both timer and loop schedulers together in DI to avoid partial wiring
- Prefer the single-scheduler TakeLast(duration) overload when no custom loop scheduling is needed
When it happens
Trigger: Calling TakeLast(source, TimeSpan.FromSeconds(5), timerScheduler, null); passing a null scheduler obtained from configuration or a factory that failed.
Common situations: Test harness that supplies a TestScheduler for the timer but forgets the loop scheduler; DI container missing a second scheduler registration; conditional scheduler resolution returning null.
Related errors
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/67641984c313072f.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.Time.cs:1290
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (duration < TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException(nameof(duration));
}
if (timerScheduler == null)
{
throw new ArgumentNullException(nameof(timerScheduler));
}
if (loopScheduler == null)
{
throw new ArgumentNullException(nameof(loopScheduler));
}
return s_impl.TakeLast(source, duration, timerScheduler, loopScheduler);
}
#endregion
#region + TakeLastBuffer +
/// <summary>
/// Returns a list with the elements within the specified duration from the end of the observable source sequence.
/// </summary>
/// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
/// <param name="source">Source sequence to take elements from.</param>
/// <param name="duration">Duration for taking elements from the end of the sequence.</param>
/// <returns>An observable sequence containing a single list with the elements taken during the specified duration from the end of the source sequence.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="duration"/> is less than TimeSpan.Zero.</exception>View on GitHub (pinned to 94b5d5ab91)