{"record":{"id":"a189e530772d0197","repo":"dotnet/reactive","slug":"value-cannot-be-null-parameter-action-eventloopscheduler","errorCode":null,"errorMessage":"Value cannot be null. (Parameter 'action')","messagePattern":"Value cannot be null\\. \\(Parameter 'action'\\)","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Source/src/System.Reactive/Concurrency/EventLoopScheduler.cs","lineNumber":141,"sourceCode":"        #endregion\n\n        #region Public methods\n\n        /// <summary>\n        /// Schedules an action to be executed after dueTime.\n        /// </summary>\n        /// <typeparam name=\"TState\">The type of the state passed to the scheduled action.</typeparam>\n        /// <param name=\"state\">State passed to the action to be executed.</param>\n        /// <param name=\"action\">Action to be executed.</param>\n        /// <param name=\"dueTime\">Relative time after which to execute the action.</param>\n        /// <returns>The disposable object used to cancel the scheduled action (best effort).</returns>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"action\"/> is <c>null</c>.</exception>\n        /// <exception cref=\"ObjectDisposedException\">The scheduler has been disposed and doesn't accept new work.</exception>\n        public override IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action)\n        {\n            if (action == null)\n            {\n                throw new ArgumentNullException(nameof(action));\n            }\n\n            var due = _stopwatch.Elapsed + dueTime;\n            var si = new ScheduledItem<TimeSpan, TState>(this, state, action, due);\n\n            lock (_gate)\n            {\n                if (_disposed)\n                {\n                    throw new ObjectDisposedException(nameof(EventLoopScheduler));\n                }\n\n                if (dueTime <= TimeSpan.Zero)\n                {\n                    _readyList.Enqueue(si);\n                    _evt.Release();\n                }\n                else","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive/Concurrency/EventLoopScheduler.cs#L123-L159","documentation":"EventLoopScheduler.Schedule<TState>(state, dueTime, action) throws ArgumentNullException when the action delegate is null. The scheduler enqueues the action into its internal ready/timer lists, so a null delegate would crash the event loop thread later; the library fails fast at the public entry point instead.","triggerScenarios":"Calling scheduler.Schedule(state, dueTime, (Func<IScheduler, TState, IDisposable>)null) directly, or passing a null delegate through wrappers such as Scheduler.Schedule extension overloads whose action argument was itself null (e.g. an uninitialized Func field or a delegate returned null from a factory).","commonSituations":"Passing a method group that resolves ambiguously and was cached as null, building schedule lambdas conditionally (if (condition) action = null), or reflection/plugin code that fails to resolve the delegate before scheduling recurring work on a dedicated event-loop thread.","solutions":["Ensure the action delegate passed to Schedule is non-null; check the expression producing it for null results.","Guard the call site: if (action == null) throw/return before calling Schedule.","If scheduling conditionally, skip the Schedule call entirely when no action is available instead of passing null."],"exampleFix":"// before\nFunc<IScheduler, int, IDisposable> work = config.UseWork ? Work : null;\nscheduler.Schedule(0, TimeSpan.FromSeconds(1), work);\n\n// after\nif (config.UseWork)\n{\n    scheduler.Schedule(0, TimeSpan.FromSeconds(1), Work);\n}","handlingStrategy":"validation","validationCode":"if (action is null) throw new ArgumentNullException(nameof(action));\nscheduler.Schedule(state, dueTime, action);","typeGuard":"static bool IsValidAction<TState>(Func<IScheduler, TState, IDisposable>? a) => a is not null;","tryCatchPattern":"try { scheduler.Schedule(state, dueTime, action); }\ncatch (ArgumentNullException ex) when (ex.ParamName == \"action\")\n{\n    // log & fix delegate wiring\n}","preventionTips":["Never store scheduling delegates in nullable fields without initialization","Assign ??= fallback no-op delegates for optional callbacks","Cover schedule call sites with unit tests that pass real lambdas"],"tags":["null-argument","scheduler","rx"],"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"}