dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'timeShift')
Error message
Value cannot be null. (Parameter 'timeShift')
What it means
The Buffer(source, timeSpan, timeShift) overload throws ArgumentNullException naming 'timeShift'. The guard is `timeShift < TimeSpan.Zero`, so the message "Value cannot be null" is misleading: the actual trigger is a negative time-shift value. timeShift controls how far apart successive buffer windows start, so it must be non-negative.
Solutions
- Clamp the shift: Math.Max(TimeSpan.Zero, timeShift) before calling Buffer.
- Review the computation producing timeShift for sign errors or subtracting unbounded values.
- Validate user/config supplied shift values at load time so negatives never reach the operator.
Example fix
// before var shift = interval - measuredDrift; // can be negative var buffer = source.Buffer(interval, shift); // after var shift = interval - measuredDrift; if (shift < TimeSpan.Zero) shift = TimeSpan.Zero; var buffer = source.Buffer(interval, shift);
Defensive patterns
Strategy: validation
Validate before calling
if (timeShift < TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(timeShift), timeShift, "Time shift must be non-negative"); var buffered = source.Buffer(timeSpan, timeShift);
Type guard
static bool IsValidShift(TimeSpan shift) => shift >= TimeSpan.Zero;
Try / catch
try { var b = source.Buffer(timeSpan, timeShift); }
catch (ArgumentNullException ex) when (ex.ParamName == "timeShift") { log.Warn("Negative timeShift passed to Buffer"); timeShift = TimeSpan.Zero; } Prevention
- Clamp measured/derived shifts (latency compensation, drift offsets) to zero minimum.
- Scan config files for accidental negative duration literals.
- Validate shift > 0 (or >= 0, per intent) in a settings-validation step.
- Keep shift computations explicit; avoid inline arithmetic that can silently go negative.
When it happens
Trigger: Calling source.Buffer(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(-2)) or passing a computed shift that went negative (e.g. shift = interval - drift with drift > interval).
Common situations: Adaptive scheduling logic where the shift is derived from measured latencies and can go negative under load, or config typos like '-2s'.
Related errors
- throw new ArgumentOutOfRangeException(nameof(window));
- Value cannot be null. (Parameter 'onCompletedAsync')
- Value cannot be null. (Parameter 'onNext')
- Value cannot be null. (Parameter 'onError')
- Value cannot be null. (Parameter 'timeSpan')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/67eb967f0df5c7b7.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Buffer.cs:92
(timeSpan, scheduler),
static async (source, state, observer) =>
{
var (sink, timer) = await AsyncObserver.Buffer(observer, state.timeSpan, state.scheduler).ConfigureAwait(false);
var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false);
return StableCompositeAsyncDisposable.Create(subscription, timer);
});
}
public static IAsyncObservable<IList<TSource>> Buffer<TSource>(this IAsyncObservable<TSource> source, TimeSpan timeSpan, TimeSpan timeShift)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
if (timeSpan < TimeSpan.Zero)
throw new ArgumentNullException(nameof(timeSpan));
if (timeShift < TimeSpan.Zero)
throw new ArgumentNullException(nameof(timeShift));
return CreateAsyncObservable<IList<TSource>>.From(
source,
(timeSpan, timeShift),
static async (source, state, observer) =>
{
var (sink, timer) = await AsyncObserver.Buffer(observer, state.timeSpan, state.timeShift).ConfigureAwait(false);
var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false);
return StableCompositeAsyncDisposable.Create(subscription, timer);
});
}
public static IAsyncObservable<IList<TSource>> Buffer<TSource>(this IAsyncObservable<TSource> source, TimeSpan timeSpan, TimeSpan timeShift, IAsyncScheduler scheduler)
{
if (source == null)
throw new ArgumentNullException(nameof(source));View on GitHub (pinned to 94b5d5ab91)