dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'timerScheduler')
Error message
Value cannot be null. (Parameter 'timerScheduler')
What it means
TakeLast(source, duration, timerScheduler, loopScheduler) throws ArgumentNullException when timerScheduler is null. The timer scheduler drives the time-based buffering of elements, so it is mandatory in this overload. The library validates arguments eagerly at the public entry point.
Solutions
- Pass a non-null scheduler such as Scheduler.Default, TaskPoolScheduler.Default, or TestScheduler
- Initialize the injected/field scheduler before building the query
- Use the simpler TakeLast(source, duration) overload which uses the default scheduler
Example fix
// before var res = source.TakeLast(TimeSpan.FromSeconds(5), null, loopScheduler); // after var res = source.TakeLast(TimeSpan.FromSeconds(5), Scheduler.Default, loopScheduler);
Defensive patterns
Strategy: validation
Validate before calling
if (timerScheduler == null) throw new ArgumentNullException(nameof(timerScheduler));
Type guard
bool HasTimerScheduler(IScheduler s) => s is not null;
Try / catch
try { var res = source.TakeLast(dur, timer, loop); }
catch (ArgumentNullException ex) when (ex.ParamName == "timerScheduler") { /* supply default scheduler */ } Prevention
- Default to Scheduler.Default when no scheduler is configured
- Verify DI registrations resolve all scheduler dependencies at startup
- In tests, initialize TestScheduler fields before composing queries
When it happens
Trigger: Calling TakeLast(source, TimeSpan.FromSeconds(5), null, loopScheduler); passing a scheduler field/property that was not initialized.
Common situations: Dependency-injected scheduler not registered in the container; static scheduler field not yet assigned in a test setup; refactoring that replaced DefaultScheduler with a nullable variable.
Related errors
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/bdd7d0abaf455deb.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.Time.cs:1285
/// This operator accumulates a buffer with a length enough to store elements for any <paramref name="duration"/> window during the lifetime of
/// the source sequence. Upon completion of the source sequence, this buffer is drained on the result sequence. This causes the result elements
/// to be delayed with <paramref name="duration"/>.
/// </remarks>
public static IObservable<TSource> TakeLast<TSource>(this IObservable<TSource> source, TimeSpan duration, IScheduler timerScheduler, IScheduler loopScheduler)
{
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>View on GitHub (pinned to 94b5d5ab91)