{"record":{"id":"722c36ea909effcb","repo":"dotnet/reactive","slug":"action-parameter-action-scheduler-async","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/Scheduler.Async.cs","lineNumber":172,"sourceCode":"        /// <summary>\n        /// Schedules work using an asynchronous method, allowing for cooperative scheduling in an imperative coding style.\n        /// </summary>\n        /// <typeparam name=\"TState\">The type of the state passed to the scheduled action.</typeparam>\n        /// <param name=\"scheduler\">Scheduler to schedule work on.</param>\n        /// <param name=\"state\">State to pass to the asynchronous method.</param>\n        /// <param name=\"action\">Asynchronous method to run the work, using Yield and Sleep operations for cooperative scheduling and injection of cancellation points.</param>\n        /// <returns>Disposable object that allows to cancel outstanding work on cooperative cancellation points or through the cancellation token passed to the asynchronous method.</returns>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"scheduler\"/> or <paramref name=\"action\"/> is <c>null</c>.</exception>\n        public static IDisposable ScheduleAsync<TState>(this IScheduler scheduler, TState state, Func<IScheduler, TState, CancellationToken, Task> action)\n        {\n            if (scheduler == null)\n            {\n                throw new ArgumentNullException(nameof(scheduler));\n            }\n\n            if (action == null)\n            {\n                throw new ArgumentNullException(nameof(action));\n            }\n\n            return ScheduleAsync_(scheduler, state, action);\n        }\n\n        /// <summary>\n        /// Schedules work using an asynchronous method, allowing for cooperative scheduling in an imperative coding style.\n        /// </summary>\n        /// <typeparam name=\"TState\">The type of the state passed to the scheduled action.</typeparam>\n        /// <param name=\"scheduler\">Scheduler to schedule work on.</param>\n        /// <param name=\"state\">State to pass to the asynchronous method.</param>\n        /// <param name=\"action\">Asynchronous method to run the work, using Yield and Sleep operations for cooperative scheduling and injection of cancellation points.</param>\n        /// <returns>Disposable object that allows to cancel outstanding work on cooperative cancellation points or through the cancellation token passed to the asynchronous method.</returns>\n        /// <exception cref=\"ArgumentNullException\"><paramref name=\"scheduler\"/> or <paramref name=\"action\"/> is <c>null</c>.</exception>\n        public static IDisposable ScheduleAsync<TState>(this IScheduler scheduler, TState state, Func<IScheduler, TState, CancellationToken, Task<IDisposable>> action)\n        {\n            if (scheduler == null)\n            {","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Source/src/System.Reactive/Concurrency/Scheduler.Async.cs#L154-L190","documentation":"ScheduleAsync<TState> validates its second argument, the async action, after validating the scheduler. Passing a null action delegate throws ArgumentNullException('action') because there is no work to schedule.","triggerScenarios":"Calling `scheduler.ScheduleAsync(state, null)` — typically when the action comes from a variable, a strategy lookup, or an optional callback that was never assigned.","commonSituations":"Conditional handler registration where the handler is missing; refactorings that made a callback optional without guarding the call site.","solutions":["Ensure the async lambda/delegate is provided and non-null at the call site.","Guard: if the handler is missing, skip the scheduling instead of calling with null.","Fix the factory/lookup that returns the action so it produces a valid delegate."],"exampleFix":"// before\nscheduler.ScheduleAsync(state, action); // action may be null\n// after\nif (action != null)\n    scheduler.ScheduleAsync(state, action);","handlingStrategy":"validation","validationCode":"if (asyncAction == null)\n    return; // or throw a domain-specific error\nscheduler.ScheduleAsync(state, asyncAction);","typeGuard":"static bool HasWork<TState>(Func<IScheduler, TState, CancellationToken, Task> a) => a is not null;","tryCatchPattern":"try { scheduler.ScheduleAsync(state, action); }\ncatch (ArgumentNullException ex) when (ex.ParamName == \"action\")\n{\n    logger.LogWarning(\"No async action configured; skipping scheduled work.\");\n}","preventionTips":["Validate delegates at the point they are assigned, not at scheduling time.","Make optional callbacks explicit (null-check before scheduling).","Prefer method groups over variables where possible so the compiler guarantees a value."],"tags":["rx","null-argument","delegate","async"],"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"}