{"record":{"id":"cd33af4b7b1469a0","repo":"dotnet/reactive","slug":"action-parameter-action","errorCode":null,"errorMessage":"action (Parameter 'action')","messagePattern":"action \\(Parameter 'action'\\)","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Source/src/System.Reactive/Concurrency/EventLoopScheduler.cs","lineNumber":191,"sourceCode":"        /// </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        /// <exception cref=\"ObjectDisposedException\">The scheduler has been disposed and doesn't accept new work.</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            return new PeriodicallyScheduledWorkItem<TState>(this, state, period, action);\n        }\n\n        private sealed class PeriodicallyScheduledWorkItem<TState> : IDisposable\n        {\n            private readonly TimeSpan _period;\n            private readonly Func<TState, TState> _action;\n            private readonly EventLoopScheduler _scheduler;\n            private readonly AsyncLock _gate = new();\n\n            private TState _state;\n            private TimeSpan _next;\n            private MultipleAssignmentDisposableValue _task;\n\n            public PeriodicallyScheduledWorkItem(EventLoopScheduler scheduler, TState state, TimeSpan period, Func<TState, TState> action)\n            {","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive/Concurrency/EventLoopScheduler.cs#L173-L209","documentation":"EventLoopScheduler.SchedulePeriodic<TState>(state, period, action) throws ArgumentNullException(nameof(action)) when the periodic action delegate is null. After validating the period, the scheduler checks the action before constructing the PeriodicallyScheduledWorkItem that will invoke it repeatedly.","triggerScenarios":"Passing (Func<TState, TState>)null as the periodic action — e.g. an uninitialized delegate field, a conditionally assigned lambda, or a factory method returning null.","commonSituations":"Periodic heartbeat/polling loops wired from configuration where the callback is registered late or via reflection and never assigned; refactorings that changed the delegate type leaving the field null.","solutions":["Verify the periodic Func is assigned before calling SchedulePeriodic.","Guard: if (action == null) throw new InvalidOperationException(\"periodic action not configured\").","Register the callback in a constructor/Initialize step guaranteed to run before scheduling."],"exampleFix":"// before\nFunc<int, int> tick = null;\nscheduler.SchedulePeriodic(0, TimeSpan.FromSeconds(1), tick); // throws\n\n// after\nFunc<int, int> tick = s => s + 1;\nscheduler.SchedulePeriodic(0, TimeSpan.FromSeconds(1), tick);","handlingStrategy":"validation","validationCode":"if (action is null) throw new ArgumentNullException(nameof(action));\nscheduler.SchedulePeriodic(state, period, action);","typeGuard":"static bool IsValidPeriodicAction<TState>(Func<TState, TState>? a) => a is not null;","tryCatchPattern":"try { scheduler.SchedulePeriodic(state, period, action); }\ncatch (ArgumentNullException ex) when (ex.ParamName == \"action\")\n{\n    // register the missing callback\n}","preventionTips":["Register periodic callbacks in constructors/initializers","Use required members or primary-constructor params for delegate dependencies","Add Debug.Assert(action != null) before scheduling in tests"],"tags":["null-argument","scheduler","periodic"],"backgroundTag":"null-argument","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"}