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

  1. Ensure the Func<IScheduler,TState,IDisposable> passed as the last argument to Schedule is a non-null delegate (e.g. (scheduler, state) => ...).
  2. 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.
  3. 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.
  4. 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

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


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)