dotnet/reactive · error · ArgumentNullException
action (Parameter 'action')
Error message
action (Parameter 'action')
What it means
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.
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.
Example fix
// before Scheduler.NewThread.Schedule(state, TimeSpan.FromSeconds(1), maybeAction); // after if (maybeAction == null) throw new ArgumentNullException(nameof(maybeAction)); Scheduler.NewThread.Schedule(state, TimeSpan.FromSeconds(1), maybeAction);
Defensive patterns
Strategy: validation
Validate before calling
if (action == null)
throw new ArgumentNullException(nameof(action));
if (dueTime < TimeSpan.Zero)
dueTime = TimeSpan.Zero; Type guard
bool CanSchedule<TState>(Func<IScheduler, TState, IDisposable> action) => action is not null;
Try / catch
try
{
return Scheduler.NewThread.Schedule(state, dueTime, action);
}
catch (ArgumentNullException ex) when (ex.ParamName == "action")
{
return Disposable.Empty;
} Prevention
- 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.
When it happens
Trigger: Calling Schedule(state, dueTime, action) (TimeSpan overload) on NewThreadScheduler (e.g. Scheduler.NewThread) with a null Func<IScheduler, TState, IDisposable>.
Common situations: 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.
Related errors
- threadFactory (Parameter 'threadFactory')
- comparer (Parameter 'comparer')
- scheduler (Parameter 'scheduler')
- action (Parameter 'action')
- scheduler (Parameter 'scheduler')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/ae603b2a5e037bd3.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Concurrency/NewThreadScheduler.cs:55
public NewThreadScheduler(Func<ThreadStart, Thread> threadFactory)
{
_threadFactory = threadFactory ?? throw new ArgumentNullException(nameof(threadFactory));
}
/// <summary>
/// Schedules an action to be executed after dueTime.
/// </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>
/// <param name="dueTime">Relative time after which to execute the action.</param>
/// <returns>The disposable object used to cancel the scheduled action (best effort).</returns>
/// <exception cref="ArgumentNullException"><paramref name="action"/> is <c>null</c>.</exception>
public override IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action)
{
if (action == null)
{
throw new ArgumentNullException(nameof(action));
}
var scheduler = new EventLoopScheduler(_threadFactory)
{
ExitIfEmpty = true
};
return scheduler.Schedule(state, dueTime, action);
}
/// <summary>
/// Schedules a long-running task by creating a new thread. Cancellation happens through polling.
/// </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 <c>null</c>.</exception>
public IDisposable ScheduleLongRunning<TState>(TState state, Action<TState, ICancelable> action)View on GitHub (pinned to 94b5d5ab91)