dotnet/reactive · error · ArgumentOutOfRangeException

ArgumentOutOfRangeException

Error message

ArgumentOutOfRangeException

What it means

The Timer(TimeSpan, TimeSpan) overload requires a non-negative period. System.Reactive.Async validates the period eagerly and throws ArgumentOutOfRangeException when period < TimeSpan.Zero, since a repeating timer cannot tick at a negative interval.

Solutions

  1. Ensure the period argument is >= TimeSpan.Zero before calling Timer.
  2. If the period is computed, clamp it: Math.Max(TimeSpan.Zero, computedPeriod).
  3. Validate/normalize any configuration value feeding the period.

Example fix

// before
var timer = AsyncObservable.Timer(dueTime, end - start); // end < start => negative
// after
var period = end > start ? end - start : TimeSpan.Zero;
var timer = AsyncObservable.Timer(dueTime, period);
Defensive patterns

Strategy: validation

Validate before calling

if (period < TimeSpan.Zero)
    throw new InvalidOperationException("Timer period must be non-negative");
var timer = AsyncObservable.Timer(dueTime, period);

Type guard

bool IsValidPeriod(TimeSpan p) => p >= TimeSpan.Zero;

Try / catch

try
{
    var timer = AsyncObservable.Timer(dueTime, period);
}
catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "period")
{
    timer = AsyncObservable.Timer(dueTime, TimeSpan.Zero);
}

Prevention

When it happens

Trigger: Calling AsyncObservable.Timer(dueTime, TimeSpan.FromSeconds(-1)) — any TimeSpan period whose value is negative.

Common situations: Period computed by subtracting timestamps (later - earlier reversed) or parsed from a user-supplied configuration value that is negative; sign errors in constants.

Related errors


AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15). Data as JSON: /api/errors/e05ea20117b3bb79. Report an issue: GitHub.

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Timer.cs:41

        }

        public static IAsyncObservable<long> Timer(DateTimeOffset dueTime)
        {
            return Create<long>(observer => AsyncObserver.Timer(observer, dueTime));
        }

        public static IAsyncObservable<long> Timer(DateTimeOffset dueTime, IAsyncScheduler scheduler)
        {
            if (scheduler == null)
                throw new ArgumentNullException(nameof(scheduler));

            return Create<long>(observer => AsyncObserver.Timer(observer, dueTime, scheduler));
        }

        public static IAsyncObservable<long> Timer(TimeSpan dueTime, TimeSpan period)
        {
            if (period < TimeSpan.Zero)
                throw new ArgumentOutOfRangeException(nameof(period));

            return Create<long>(observer => AsyncObserver.Timer(observer, dueTime, period));
        }

        public static IAsyncObservable<long> Timer(TimeSpan dueTime, TimeSpan period, IAsyncScheduler scheduler)
        {
            if (period < TimeSpan.Zero)
                throw new ArgumentOutOfRangeException(nameof(period));
            if (scheduler == null)
                throw new ArgumentNullException(nameof(scheduler));

            return Create<long>(observer => AsyncObserver.Timer(observer, dueTime, period, scheduler));
        }

        public static IAsyncObservable<long> Timer(DateTimeOffset dueTime, TimeSpan period)
        {
            if (period < TimeSpan.Zero)
                throw new ArgumentOutOfRangeException(nameof(period));

View on GitHub (pinned to 94b5d5ab91)