dotnet/reactive · error · ArgumentOutOfRangeException

Specified argument was out of the range of valid values…

Error message

Specified argument was out of the range of valid values. (Parameter 'period')

What it means

DefaultScheduler.SchedulePeriodic<TState> schedules a recurring state-transforming action; the period is checked first and must be greater than or equal to TimeSpan.Zero. Negative periods are rejected with ArgumentOutOfRangeException before the action null-check and work-item creation.

Solutions

  1. Validate the period before scheduling: if (period < TimeSpan.Zero) throw new ArgumentException(...).
  2. Clamp to TimeSpan.Zero or a sensible minimum instead of passing the raw value.
  3. Fix the interval computation/source so it can no longer produce negative TimeSpans.

Example fix

// before
var period = end - start; // negative when start > end
scheduler.SchedulePeriodic(0L, period, n => n + 1);

// after
var period = end - start;
if (period < TimeSpan.Zero) period = TimeSpan.FromMinutes(1);
scheduler.SchedulePeriodic(0L, period, n => n + 1);
Defensive patterns

Strategy: validation

Validate before calling

if (period < TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(period));
if (period == TimeSpan.Zero) period = TimeSpan.FromMilliseconds(1); // or keep Zero intentionally
scheduler.SchedulePeriodic(state, period, next);

Try / catch

try { scheduler.SchedulePeriodic(state, period, next); } catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "period") { /* clamp period and retry */ }

Prevention

When it happens

Trigger: Calling scheduler.SchedulePeriodic(state, TimeSpan.FromSeconds(-1), next) or any negative TimeSpan period, often from a computed or configured interval.

Common situations: Polling intervals read from config where a negative value slipped in, subtracting DateTimes to get the interval, or unit tests probing boundary behavior of periodic scheduling.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Concurrency/DefaultScheduler.cs:97

            return workItem;
        }

        /// <summary>
        /// Schedules a periodic piece of work, using a System.Threading.Timer object.
        /// </summary>
        /// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam>
        /// <param name="state">Initial state passed to the action upon the first iteration.</param>
        /// <param name="period">Period for running the work periodically.</param>
        /// <param name="action">Action to be executed, potentially updating the state.</param>
        /// <returns>The disposable object used to cancel the scheduled recurring action (best effort).</returns>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="period"/> is less than <see cref="TimeSpan.Zero"/>.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="action"/> is <c>null</c>.</exception>
        public IDisposable SchedulePeriodic<TState>(TState state, TimeSpan period, Func<TState, TState> action)
        {
            if (period < TimeSpan.Zero)
            {
                throw new ArgumentOutOfRangeException(nameof(period));
            }

            if (action == null)
            {
                throw new ArgumentNullException(nameof(action));
            }

            return new PeriodicallyScheduledWorkItem<TState>(state, period, action);
        }

        private sealed class PeriodicallyScheduledWorkItem<TState> : IDisposable
        {
            private TState _state;
            private Func<TState, TState> _action;
            private readonly IDisposable _cancel;
            private readonly AsyncLock _gate = new();

            public PeriodicallyScheduledWorkItem(TState state, TimeSpan period, Func<TState, TState> action)

View on GitHub (pinned to 94b5d5ab91)