dotnet/reactive · error · ArgumentNullException
action (Parameter 'action')
Error message
action (Parameter 'action')
What it means
The same ScheduledItem<TAbsolute, TValue> constructor throws ArgumentNullException when the action argument is null. The action (Func<IScheduler, TValue, IDisposable>) is invoked when the item becomes due; without it the scheduler would invoke a null delegate when the queue is drained.
Solutions
- Ensure a non-null action delegate is supplied; use '(_, __) => Disposable.Empty' for no-op items.
- Validate the action in your wrapper before constructing the ScheduledItem.
- Trace the scheduling call chain (Enqueue/Invoke paths) to find where the null originates.
- Prefer building items via IScheduler.Schedule extension methods, which validate arguments.
Example fix
// before var item = new ScheduledItem<DateTimeOffset, int>(scheduler, state, action /* null */, dueTime, comparer); // after if (action == null) throw new ArgumentNullException(nameof(action)); var item = new ScheduledItem<DateTimeOffset, int>(scheduler, state, action, dueTime, comparer);
Defensive patterns
Strategy: validation
Validate before calling
if (action == null)
throw new ArgumentNullException(nameof(action)); Type guard
bool HasAction<TValue>(Func<IScheduler, TValue, IDisposable> action) => action is not null;
Try / catch
try
{
var item = new ScheduledItem<DateTimeOffset, TState>(scheduler, state, action, dueTime, comparer);
}
catch (ArgumentNullException ex) when (ex.ParamName == "action")
{
var item = new ScheduledItem<DateTimeOffset, TState>(scheduler, state, (_, __) => Disposable.Empty, dueTime, comparer);
} Prevention
- Validate delegates before constructing materialized work items.
- Use '(_, __) => Disposable.Empty' as a no-op item action.
- Prefer IScheduler.Schedule extensions, which validate arguments, over direct ScheduledItem construction.
When it happens
Trigger: Constructing ScheduledItem with a null Func<IScheduler, TValue, IDisposable>, often from generic scheduling helpers that pass through user-provided lambdas without validation.
Common situations: Custom scheduler implementations re-implementing Schedule internally; test fakes building materialized work items; refactoring where a lambda was replaced by a null-returning factory method.
Related errors
- threadFactory (Parameter 'threadFactory')
- action (Parameter 'action')
- comparer (Parameter 'comparer')
- scheduler (Parameter 'scheduler')
- scheduler (Parameter 'scheduler')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/67dac0f40d21a187.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Concurrency/ScheduledItem.cs:187
private readonly IScheduler _scheduler;
private readonly TValue _state;
private readonly Func<IScheduler, TValue, IDisposable> _action;
/// <summary>
/// Creates a materialized work item.
/// </summary>
/// <param name="scheduler">Recursive scheduler to invoke the scheduled action with.</param>
/// <param name="state">State to pass to the scheduled action.</param>
/// <param name="action">Scheduled action.</param>
/// <param name="dueTime">Time at which to run the scheduled action.</param>
/// <param name="comparer">Comparer used to compare work items based on their scheduled time.</param>
/// <exception cref="ArgumentNullException"><paramref name="scheduler"/> or <paramref name="action"/> or <paramref name="comparer"/> is <c>null</c>.</exception>
public ScheduledItem(IScheduler scheduler, TValue state, Func<IScheduler, TValue, IDisposable> action, TAbsolute dueTime, IComparer<TAbsolute> comparer)
: base(dueTime, comparer)
{
_scheduler = scheduler ?? throw new ArgumentNullException(nameof(scheduler));
_state = state;
_action = action ?? throw new ArgumentNullException(nameof(action));
}
/// <summary>
/// Creates a materialized work item.
/// </summary>
/// <param name="scheduler">Recursive scheduler to invoke the scheduled action with.</param>
/// <param name="state">State to pass to the scheduled action.</param>
/// <param name="action">Scheduled action.</param>
/// <param name="dueTime">Time at which to run the scheduled action.</param>
/// <exception cref="ArgumentNullException"><paramref name="scheduler"/> or <paramref name="action"/> is <c>null</c>.</exception>
public ScheduledItem(IScheduler scheduler, TValue state, Func<IScheduler, TValue, IDisposable> action, TAbsolute dueTime)
: this(scheduler, state, action, dueTime, Comparer<TAbsolute>.Default)
{
}
/// <summary>
/// Invokes the scheduled action with the supplied recursive scheduler and state.
/// </summary>View on GitHub (pinned to 94b5d5ab91)