dotnet/reactive · error · ArgumentOutOfRangeException

period

Error message

period

What it means

Interval validates that the period is non-negative; a negative TimeSpan has no valid timing meaning, so ArgumentOutOfRangeException fires before the timer-based observable is created. Fix: pass TimeSpan.Zero or a positive duration.

Solutions

  1. Ensure the period is >= TimeSpan.Zero; clamp with Math.Max(TimeSpan.Zero, period).
  2. Fix the computation producing the negative TimeSpan (check subtraction order of DateTime/Stopwatch values).
  3. Use TimeSpan.Zero or a positive duration for 'emit as soon as scheduled' semantics if that was intended.

Example fix

// before
var period = end - start; // may be negative
var xs = AsyncObservable.Interval(period);
// after
var period = end > start ? end - start : TimeSpan.Zero;
var xs = AsyncObservable.Interval(period);
Defensive patterns

Strategy: validation

Validate before calling

if (period < TimeSpan.Zero) throw new ArgumentException("period must be >= TimeSpan.Zero", nameof(period));
var safePeriod = TimeSpan.FromTicks(Math.Max(0, period.Ticks));

Type guard

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

Try / catch

try { var xs = AsyncObservable.Interval(period); }
catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "period") { /* clamp and retry */ }

Prevention

When it happens

Trigger: Calling AsyncObservable.Interval(TimeSpan.FromMilliseconds(-1)) or any negative TimeSpan, often from a computed or parsed interval value that ended up negative (e.g. subtracting timestamps).

Common situations: Config values parsed into TimeSpan with wrong sign, diffing two DateTimes in the wrong order, or default(TimeSpan) mistakes combined with arithmetic producing negative durations.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Interval.cs:15

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT License.
// See the LICENSE file in the project root for more information. 

using System.Reactive.Concurrency;
using System.Threading.Tasks;

namespace System.Reactive.Linq
{
    public partial class AsyncObservable
    {
        public static IAsyncObservable<long> Interval(TimeSpan period)
        {
            if (period < TimeSpan.Zero)
                throw new ArgumentOutOfRangeException(nameof(period));

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

        public static IAsyncObservable<long> Interval(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.Interval(observer, period, scheduler));
        }
    }

    public partial class AsyncObserver
    {
        public static ValueTask<IAsyncDisposable> Interval(IAsyncObserver<long> observer, TimeSpan period) => Timer(observer, period, period);

View on GitHub (pinned to 94b5d5ab91)