{"record":{"id":"ae603b2a5e037bd3","repo":"dotnet/reactive","slug":"action-parameter-action-newthreadscheduler","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/NewThreadScheduler.cs","lineNumber":55,"sourceCode":"        public NewThreadScheduler(Func<ThreadStart, Thread> threadFactory)\n        {\n            _threadFactory = threadFactory ?? throw new ArgumentNullException(nameof(threadFactory));\n        }\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        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 scheduler = new EventLoopScheduler(_threadFactory)\n            {\n                ExitIfEmpty = true\n            };\n            return scheduler.Schedule(state, dueTime, action);\n        }\n\n        /// <summary>\n        /// Schedules a long-running task by creating a new thread. Cancellation happens through polling.\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        /// <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        public IDisposable ScheduleLongRunning<TState>(TState state, Action<TState, ICancelable> action)","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive/Concurrency/NewThreadScheduler.cs#L37-L73","documentation":"NewThreadScheduler.Schedule<TState>(state, dueTime, action) throws ArgumentNullException when the action delegate is null. This override creates an EventLoopScheduler per work item and delegates the work to it; a null action would be scheduled with nothing to run. Validation happens immediately before any thread is created.","triggerScenarios":"Calling Schedule(state, dueTime, action) (TimeSpan overload) on NewThreadScheduler (e.g. Scheduler.NewThread) with a null Func<IScheduler, TState, IDisposable>.","commonSituations":"Custom operator or extension code forwarding null lambdas; delayed work built from optional callbacks (e.g. timeout handlers) that are absent; migrating code from SyncContext schedulers that tolerated nulls.","solutions":["Provide a non-null action delegate to Schedule.","Substitute a no-op action returning Disposable.Empty when there is nothing to do.","Validate arguments at the boundary of your wrapper before calling Schedule.","Trace callers (Subscribe/Timer paths) to find where the null delegate originates."],"exampleFix":"// before\nScheduler.NewThread.Schedule(state, TimeSpan.FromSeconds(1), maybeAction);\n// after\nif (maybeAction == null) throw new ArgumentNullException(nameof(maybeAction));\nScheduler.NewThread.Schedule(state, TimeSpan.FromSeconds(1), maybeAction);","handlingStrategy":"validation","validationCode":"if (action == null)\n    throw new ArgumentNullException(nameof(action));\nif (dueTime < TimeSpan.Zero)\n    dueTime = TimeSpan.Zero;","typeGuard":"bool CanSchedule<TState>(Func<IScheduler, TState, IDisposable> action) => action is not null;","tryCatchPattern":"try\n{\n    return Scheduler.NewThread.Schedule(state, dueTime, action);\n}\ncatch (ArgumentNullException ex) when (ex.ParamName == \"action\")\n{\n    return Disposable.Empty;\n}","preventionTips":["Wrap Scheduler.NewThread calls in helper methods that validate delegates once.","Use no-op lambdas for optional work instead of nulls.","Add contract tests for all Schedule overloads with null arguments."],"tags":["rx","scheduler","threading","argument-null","csharp"],"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"}