{"record":{"id":"7831c0486b6f3984","repo":"dotnet/reactive","slug":"period-parameter-period","errorCode":null,"errorMessage":"period (Parameter 'period')","messagePattern":"period \\(Parameter 'period'\\)","errorType":"exception","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Source/src/System.Reactive/Concurrency/NewThreadScheduler.cs","lineNumber":111,"sourceCode":"\n            return d;\n        }\n\n        /// <summary>\n        /// Schedules a periodic piece of work by creating a new thread that goes to sleep when work has been dispatched and wakes up again at the next periodic due time.\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            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 periodic = new Periodic<TState>(state, period, action);\n\n            var thread = _threadFactory(periodic.Run);\n            thread.Start();\n\n            return periodic;\n        }\n\n        private sealed class Periodic<TState> : IDisposable\n        {\n            private readonly IStopwatch _stopwatch;","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive/Concurrency/NewThreadScheduler.cs#L93-L129","documentation":"NewThreadScheduler.SchedulePeriodic<TState>(state, period, action) throws ArgumentOutOfRangeException when period is less than TimeSpan.Zero. A periodic schedule needs a non-negative interval; a negative period is meaningless and would break the underlying Periodic timer setup.","triggerScenarios":"Calling SchedulePeriodic with a negative TimeSpan, e.g. computed as 'endTime - now' after the deadline passed, or from configuration where an interval parses as negative.","commonSituations":"Polling intervals derived from a deadline already in the past; misparsed config strings ('-00:00:05'); unit tests passing TimeSpan.MinValue as a sentinel; arithmetic like TimeSpan.FromMilliseconds(-1) from metrics.","solutions":["Clamp the period before scheduling: 'if (period < TimeSpan.Zero) period = TimeSpan.Zero;'.","Use TimeSpan.FromMilliseconds(Timeout.Infinite) semantics only where the API supports it; otherwise pick a positive default.","Validate configured intervals at startup and fail fast with a clear message.","Recompute deadline-derived intervals with Math.Max(TimeSpan.Zero, deadline - now)."],"exampleFix":"// before\nvar period = deadline - DateTime.UtcNow;\nscheduler.SchedulePeriodic(state, period, Tick);\n// after\nvar period = deadline - DateTime.UtcNow;\nif (period < TimeSpan.Zero) period = TimeSpan.Zero;\nscheduler.SchedulePeriodic(state, period, Tick);","handlingStrategy":"validation","validationCode":"if (period < TimeSpan.Zero)\n    throw new ArgumentOutOfRangeException(nameof(period));","typeGuard":"bool IsValidPeriod(TimeSpan period) => period >= TimeSpan.Zero;","tryCatchPattern":"try\n{\n    scheduler.SchedulePeriodic(state, period, action);\n}\ncatch (ArgumentOutOfRangeException ex) when (ex.ParamName == \"period\")\n{\n    period = TimeSpan.Zero; // or a sane default, then reschedule\n}","preventionTips":["Clamp deadline-derived intervals with Math.Max(TimeSpan.Zero, delta).","Validate configured intervals at startup, not at scheduling time.","Never use negative TimeSpans as sentinels in scheduling code."],"tags":["rx","scheduler","argument-out-of-range","timespan","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"}