dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'action')
Error message
Value cannot be null. (Parameter 'action')
What it means
This is an ArgumentNullException thrown by SchedulerWrapper.Schedule<TState>(TState, Func<IScheduler,TState,IDisposable>) when the scheduling action delegate is null. SchedulerWrapper decorates an IScheduler and forwards calls to the inner scheduler after wrapping the action, so it validates the delegate up front to avoid a null surfacing later inside the wrapped schedule pipeline.
Solutions
- Ensure the Func<IScheduler,TState,IDisposable> passed as the last argument to Schedule is a non-null delegate (e.g. (scheduler, state) => ...).
- If the delegate comes from a variable or factory, check it for null before calling Schedule and provide a default no-op action returning Disposable.Empty.
- Pass null state instead of a null action when the intent was to schedule without a value; only the action parameter may not be null.
- Review code that builds the delegate dynamically (reflection, conditional expressions) and add a null check at construction time.
Example fix
// before Func<IScheduler, int, IDisposable> action = GetAction(); schedulerWrapper.Schedule(42, action); // action may be null // after Func<IScheduler, int, IDisposable> action = GetAction() ?? ((s, st) => Disposable.Empty); schedulerWrapper.Schedule(42, action);
Defensive patterns
Strategy: validation
Validate before calling
if (action == null) throw new InvalidOperationException("Schedule requires a non-null action delegate");
schedulerWrapper.Schedule(state, action); Type guard
bool IsValidAction<TState>(Func<IScheduler, TState, IDisposable> action) => action != null;
Try / catch
try
{
schedulerWrapper.Schedule(state, action);
}
catch (ArgumentNullException ex) when (ex.ParamName == "action")
{
schedulerWrapper.Schedule(state, (s, st) => Disposable.Empty);
} Prevention
- Never build schedule actions via expressions that can return null; default to a no-op returning Disposable.Empty.
- Null-check delegate arguments where they are created, not at the scheduling call site.
- Avoid storing callbacks in uninitialized fields; initialize them with a default no-op lambda.
- When scheduling optional work, branch around the Schedule call instead of passing null.
When it happens
Trigger: Calling scheduler.Schedule(state, action) (immediate, no due time) on a SchedulerWrapper with a null Func<IScheduler,TState,IDisposable>, typically because a lambda variable was null, a conditional factory returned null, or a method group bound to a null instance.
Common situations: Passing the result of a function that conditionally returns a delegate; storing callbacks in a nullable field or property that has not been initialized; refactoring code where the action lambda was accidentally removed or replaced by a null-returning expression.
Related errors
- Value cannot be null. (Parameter 'source')
- Value cannot be null. (Parameter 'scheduler')
- scheduler (Value cannot be null)
- action (Value cannot be null)
- scheduler (Value cannot be null)
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/fe27dee496eea61d.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Concurrency/SchedulerWrapper.cs:36
protected SchedulerWrapper(IScheduler scheduler)
{
_scheduler = scheduler;
}
protected SchedulerWrapper(IScheduler scheduler, ConditionalWeakTable<IScheduler, IScheduler> cache)
{
_scheduler = scheduler;
_cache = cache;
}
public DateTimeOffset Now => _scheduler.Now;
public IDisposable Schedule<TState>(TState state, Func<IScheduler, TState, IDisposable> action)
{
if (action == null)
{
throw new ArgumentNullException(nameof(action));
}
return _scheduler.Schedule(state, Wrap(action));
}
public IDisposable Schedule<TState>(TState state, TimeSpan dueTime, Func<IScheduler, TState, IDisposable> action)
{
if (action == null)
{
throw new ArgumentNullException(nameof(action));
}
return _scheduler.Schedule(state, dueTime, Wrap(action));
}
public IDisposable Schedule<TState>(TState state, DateTimeOffset dueTime, Func<IScheduler, TState, IDisposable> action)
{
if (action == null)View on GitHub (pinned to 94b5d5ab91)