{"record":{"id":"191d4bad8fe92a00","repo":"dotnet/reactive","slug":"period-specified-argument-was-out-of-the-range-of-valid","errorCode":null,"errorMessage":"period (Specified argument was out of the range of valid values)","messagePattern":"period \\(Specified argument was out of the range of valid values\\)","errorType":"validation","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Source/src/System.Reactive/Concurrency/Scheduler.Services.Emulation.cs","lineNumber":37,"sourceCode":"        /// </summary>\n        /// <typeparam name=\"TState\">The type of the state passed to the scheduled action.</typeparam>\n        /// <param name=\"scheduler\">The scheduler to run periodic work on.</param>\n        /// <param name=\"state\">Initial state passed to the action upon the first iteration.</param>\n        /// <param name=\"period\">Period for running the work periodically.</param>\n        /// <param name=\"action\">Action to be executed, potentially updating the state.</param>\n        /// <returns>The disposable object used to cancel the scheduled recurring action (best effort).</returns>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"scheduler\"/> or <paramref name=\"action\"/> is <c>null</c>.</exception>\n        /// <exception cref=\"ArgumentOutOfRangeException\"><paramref name=\"period\"/> is less than <see cref=\"TimeSpan.Zero\"/>.</exception>\n        public static IDisposable SchedulePeriodic<TState>(this IScheduler scheduler, TState state, TimeSpan period, Func<TState, TState> action)\n        {\n            if (scheduler == null)\n            {\n                throw new ArgumentNullException(nameof(scheduler));\n            }\n\n            if (period < TimeSpan.Zero)\n            {\n                throw new ArgumentOutOfRangeException(nameof(period));\n            }\n\n            if (action == null)\n            {\n                throw new ArgumentNullException(nameof(action));\n            }\n\n            return SchedulePeriodic_(scheduler, state, period, action);\n        }\n\n        /// <summary>\n        /// Schedules a periodic piece of work by dynamically discovering the scheduler's capabilities.\n        /// If the scheduler supports periodic scheduling, the request will be forwarded to the periodic scheduling implementation.\n        /// If the scheduler provides stopwatch functionality, the periodic task will be emulated using recursive scheduling with a stopwatch to correct for time slippage.\n        /// Otherwise, the periodic task will be emulated using recursive scheduling.\n        /// </summary>\n        /// <typeparam name=\"TState\">The type of the state passed to the scheduled action.</typeparam>\n        /// <param name=\"scheduler\">Scheduler to execute the action on.</param>","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive/Concurrency/Scheduler.Services.Emulation.cs#L19-L55","documentation":"SchedulePeriodic<TState>(IScheduler, TState, TimeSpan, Func<TState,TState>) throws ArgumentOutOfRangeException when period < TimeSpan.Zero. A negative period is meaningless for a periodic timer; Rx rejects it up front instead of scheduling an invalid sequence of ticks. TimeSpan.Zero is allowed (period invoked immediately/repeatedly per scheduler semantics).","triggerScenarios":"Calling SchedulePeriodic with a TimeSpan computed to be negative, e.g. TimeSpan.FromSeconds(-1), a subtraction of DateTime values yielding negative duration, or deserialized/converted config values such as 'PT-5S' producing a negative TimeSpan.","commonSituations":"Configuration parsing errors where a delay/interval value is negative, subtracting a later timestamp from an earlier one to compute an interval, integer arithmetic overflow wrapping negative, or unit confusion (treating a value in seconds when it was milliseconds).","solutions":["Clamp or validate the period before calling: if (period < TimeSpan.Zero) period = TimeSpan.Zero; or throw with your own message","Fix the computation producing the negative TimeSpan (check the order of subtraction operands and units)","If the interval comes from config, validate it at load time and reject negative values with a clear error"],"exampleFix":"// before\nvar period = nextRun - DateTime.Now; // can be negative\nscheduler.SchedulePeriodic(state, period, s => s);\n\n// after\nvar period = nextRun - DateTime.Now;\nif (period < TimeSpan.Zero) period = TimeSpan.Zero;\nscheduler.SchedulePeriodic(state, period, s => s);","handlingStrategy":"validation","validationCode":"if (period < TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(period), period, \"Period must be non-negative\");\nscheduler.SchedulePeriodic(state, period, action);","typeGuard":"bool IsValidPeriod(TimeSpan p) => p >= TimeSpan.Zero;","tryCatchPattern":"try { scheduler.SchedulePeriodic(state, period, action); }\ncatch (ArgumentOutOfRangeException ex) when (ex.ParamName == \"period\") { /* clamp to Zero or report config error */ }","preventionTips":["Validate all interval config values at startup","Use System.TimeSpan.From* factories rather than raw ticks arithmetic","Check subtraction order when computing intervals from timestamps"],"tags":["rx","scheduler","timespan","range-check"],"backgroundTag":"argument-out-of-range","analyzedSha":"94b5d5ab912789f5abe9a72138a25bbd716fe59c","analyzedAt":"2026-09-15T02:26:24.759Z","contentChangedAt":"2026-09-15T02:26:24.759Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}