{"record":{"id":"9144e7da7212f364","repo":"dotnet/reactive","slug":"period-coredispatcherscheduler","errorCode":null,"errorMessage":"period","messagePattern":"period","errorType":"exception","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Source/src/System.Reactive/Platforms/WinRT/Concurrency/CoreDispatcherScheduler.cs","lineNumber":234,"sourceCode":"        /// <summary>\n        /// Schedules a periodic piece of work on the dispatcher, using a <see cref=\"DispatcherQueueTimer\"/> object.\n        /// </summary>\n        /// <typeparam name=\"TState\">The type of the state passed to the scheduled action.</typeparam>\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=\"action\"/> is <c>null</c>.</exception>\n        /// <exception cref=\"ArgumentOutOfRangeException\"><paramref name=\"period\"/> is less than <see cref=\"TimeSpan.Zero\"/>.</exception>\n        public IDisposable SchedulePeriodic<TState>(TState state, TimeSpan period, Func<TState, TState> action)\n        {\n            //\n            // According to MSDN documentation, the default is TimeSpan.Zero, so that's definitely valid.\n            // Empirical observation - negative values seem to be normalized to TimeSpan.Zero, but let's not go there.\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            var timer = CreateDispatcherQueue().CreateTimer();\n\n            var state1 = state;\n\n            timer.Tick += (o, e) =>\n            {\n                state1 = action(state1);\n            };\n\n            timer.Interval = period;\n            timer.Start();","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive/Platforms/WinRT/Concurrency/CoreDispatcherScheduler.cs#L216-L252","documentation":"CoreDispatcherScheduler.SchedulePeriodic<TState>(state, period, action) throws ArgumentOutOfRangeException because 'period' is negative. A periodic timer cannot run at a negative interval; the WinRT dispatcher timer only accepts TimeSpan.Zero or positive periods, so Rx rejects negative values eagerly.","triggerScenarios":"Calling SchedulePeriodic with a negative TimeSpan, e.g. SchedulePeriodic(state, TimeSpan.FromSeconds(-1), action), often from a computed duration like a negative difference between DateTimes or a misconfigured setting.","commonSituations":"Computing the period from (target - DateTime.Now) after the target has already passed; config/app-setting values parsed with a minus sign; arithmetic sign errors when building polling intervals.","solutions":["Pass a positive (or zero) TimeSpan as 'period'; clamp negative values with something like period < TimeSpan.Zero ? TimeSpan.Zero : period.","Fix the computation producing the negative duration (e.g. use Math.Max(TimeSpan.Zero, target - now)).","Validate configured interval values at startup before scheduling."],"exampleFix":"// before\nvar elapsed = DateTime.Now - dueTime; // negative when dueTime is in the future\nscheduler.SchedulePeriodic(0, elapsed, Tick);\n// after\nvar period = DateTime.Now < dueTime ? dueTime - DateTime.Now : TimeSpan.Zero;\nscheduler.SchedulePeriodic(0, period, Tick);","handlingStrategy":"validation","validationCode":"// csharp\nif (period < TimeSpan.Zero)\n    period = TimeSpan.Zero; // or throw with your own message\nscheduler.SchedulePeriodic(state, period, action);","typeGuard":"null","tryCatchPattern":"// csharp\ntry { d = scheduler.SchedulePeriodic(state, period, action); }\ncatch (ArgumentOutOfRangeException ex) when (ex.ParamName == \"period\") { log.Error(\"Negative periodic period\", ex); d = Disposable.Empty; }","preventionTips":["Compute periods with Math.Max(TimeSpan.Zero, ...) when using elapsed-time arithmetic","Validate configured intervals at application startup","Unit-test interval computations with edge-case clocks"],"tags":["argument-out-of-range","scheduler","timer","csharp"],"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"}