dotnet/reactive · error · ArgumentNullException
action (Parameter 'action')
Error message
action (Parameter 'action')
What it means
ThreadPoolScheduler.Windows.Schedule<TState>(state, action) throws ArgumentNullException because the 'action' to execute on the Windows thread pool is null. The scheduler wraps the action in a UserWorkItem for the WinRT thread pool, so a null delegate is rejected immediately.
Solutions
- Pass a non-null action delegate; initialize the variable holding it.
- Throw a descriptive exception in your own code when the delegate is missing instead of letting the scheduler fail.
- Skip scheduling entirely when there is no work to run.
Example fix
// before
scheduler.Schedule(state, (Func<IScheduler, int, IDisposable>)null);
// after
scheduler.Schedule(state, (s, st) => { RunWork(st); return Disposable.Empty; }); Defensive patterns
Strategy: validation
Validate before calling
// csharp
if (action == null)
return Disposable.Empty; // nothing to schedule
scheduler.Schedule(state, action); Type guard
// csharp bool CanSchedule<TState>(Func<IScheduler, TState, IDisposable> action) => action is not null;
Try / catch
// csharp
try { d = scheduler.Schedule(state, action); }
catch (ArgumentNullException ex) when (ex.ParamName == "action") { log.Warn("Work item was null"); d = Disposable.Empty; } Prevention
- Prefer inline lambdas over delegate variables that can be null
- Assert non-null delegates in debug builds before scheduling
- Keep scheduling code away from conditional callback creation
When it happens
Trigger: Calling ThreadPoolScheduler.Instance.Schedule(state, (scheduler, state) => ...) with a null Func<IScheduler,TState,IDisposable> — typically a null delegate variable or method returning null.
Common situations: Uninitialized fields holding work items; dependency-injected delegates not wired up; refactoring a lambda into a method whose return became null.
Related errors
- action (Parameter 'action')
- action (Value cannot be null)
- ArgumentNullException: action
- ArgumentNullException: action
- ArgumentNullException (default message: Value cannot be…
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/ae371b6e2b3e6de9.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Platforms/WinRT/Concurrency/ThreadPoolScheduler.Windows.cs:95
/// <summary>
/// Gets the options that configure how work is scheduled.
/// </summary>
[Obsolete("If you require the UWP-specific features of ThreadPoolScheduler use the WindowsRuntimeThreadPoolScheduler in the System.Reactive.WindowsRuntime package. This property will be removed in a future version (because UWP applications will end up with the same ThreadPoolScheduler as all other application types).")]
public WorkItemOptions Options { get; }
/// <summary>
/// Schedules an action to be executed.
/// </summary>
/// <typeparam name="TState">The type of the state passed to the scheduled action.</typeparam>
/// <param name="state">State passed to the action to be executed.</param>
/// <param name="action">Action to be executed.</param>
/// <returns>The disposable object used to cancel the scheduled action (best effort).</returns>
/// <exception cref="ArgumentNullException"><paramref name="action"/> is null.</exception>
public override IDisposable Schedule<TState>(TState state, Func<IScheduler, TState, IDisposable> action)
{
if (action == null)
throw new ArgumentNullException(nameof(action));
var userWorkItem = new UserWorkItem<TState>(this, state, action);
#pragma warning disable CS0618 // Type or member is obsolete.
// A note on obsolescence:
// The compiler complains because this uses Priority and Options. We could mark the
// whole method as obsolete, but this would be slightly misleading because when we
// eventually remove the obsoleted UWP support, this whole ThreadPoolScheduler will
// be replaced by the non-UWP implementation, and that continues to support this
// Schedule overload. So the method isn't really obsolete - it will continue to be
// available to UWP apps even after we've removed all UWP-specific code from
// System.Reactive.
// An argument in favour of marking the method as Obsolete anyway is that the
// behaviour will change once we remove UWP code from System.Reactive. However,
// the change in behaviour is interesting only if you've specified either
// priority or options for the work items, and all the public methods we supply
// for that *are* obsolete. So anyone relying on that behaviour will already have
// received an obsolescence warning, and should move to WindowsRuntimeThreadPoolScheduler.View on GitHub (pinned to 94b5d5ab91)