dotnet/reactive · error · ArgumentNullException
action (Parameter 'action')
Error message
action (Parameter 'action')
What it means
ImmediateScheduler.Schedule<TState>(state, action) throws ArgumentNullException when action is null. The immediate scheduler runs the action synchronously on the calling thread, and since there is no queue, it validates the delegate at the very start.
Solutions
- Pass a non-null delegate to Schedule; trace the null back to the lambda/field that was never assigned.
- Validate delegates at your API boundary before invoking Rx scheduling.
- Use a fallback no-op action if executing nothing is acceptable: (s, st) => Disposable.Empty.
Example fix
// before
Action? userCallback = maybeNull;
Scheduler.Immediate.Schedule(0, (s, st) => { userCallback!(); return Disposable.Empty; }); // throws if userCallback null
// after
if (userCallback != null)
Scheduler.Immediate.Schedule(0, (s, st) => { userCallback(); return Disposable.Empty; }); Defensive patterns
Strategy: validation
Validate before calling
if (action is null) return Disposable.Empty; // or throw earlier with context Scheduler.Immediate.Schedule(state, action);
Type guard
static bool HasAction<TState>(Func<IScheduler, TState, IDisposable>? a) => a is not null;
Try / catch
try { Scheduler.Immediate.Schedule(state, action); }
catch (ArgumentNullException ex) when (ex.ParamName == "action")
{
// delegate was null upstream
} Prevention
- Null-check user callbacks at your API boundary
- Prefer optional-callback patterns over nullable Funcs
- Run Rx operator tests with fully initialized delegates
When it happens
Trigger: Calling Scheduler.Immediate.Schedule(state, null), or an Rx operator/timer helper (e.g. via InvokeRec, ScheduleAsync) receiving a null delegate and forwarding it to the immediate scheduler.
Common situations: Unit tests exercising Rx operators with hand-written schedulers; code paths where a lambda is built from a nullable callback and immediately executed synchronously via Immediate.
Related errors
- action (Parameter 'action')
- action (Parameter 'action')
- action (Parameter 'action')
- action (Parameter 'action')
- action (Parameter 'action')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/19daa0285eaf38a9.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Concurrency/ImmediateScheduler.cs:38
/// <summary>
/// Gets the singleton instance of the immediate scheduler.
/// </summary>
public static ImmediateScheduler Instance => StaticInstance.Value;
/// <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));
}
return action(new AsyncLockScheduler(), state);
}
/// <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 null.</exception>
public override IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action)
{
if (action == null)
{View on GitHub (pinned to 94b5d5ab91)