dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'iterate')

Error message

Value cannot be null. (Parameter 'iterate')

What it means

The scheduler-overload of Observable.Generate throws ArgumentNullException when the 'iterate' delegate is null. The scheduled loop must advance state on every tick, so Rx rejects a null step function at the public API boundary.

Solutions

  1. Provide a non-null iterate function such as i => i + 1
  2. Fall back to a no-op/terminating step if the step is optional
  3. Assert the delegate is not null before invoking

Example fix

// before
Observable.Generate(0, c, null, r, Scheduler.Default)
// after
Observable.Generate(0, c, i => i + 1, r, Scheduler.Default)
Defensive patterns

Strategy: validation

Validate before calling

if (iterate == null) throw new ArgumentNullException(nameof(iterate));

Type guard

bool HasIterate(Func<TState,TState> it) => it is not null;

Try / catch

try { Observable.Generate(state, cond, it, sel, sched); } catch (ArgumentNullException ex) when (ex.ParamName == "iterate") { /* fix step function */ }

Prevention

When it happens

Trigger: Calling Observable.Generate<TState, TResult>(initialState, condition, null, resultSelector, scheduler), e.g. a step lambda that failed to initialize.

Common situations: Timer-like generators whose state-advance function is injected and not registered; mock setups returning null.

Related errors


AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15). Data as JSON: /api/errors/ba992af2585e8290. Report an issue: GitHub.

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.Creation.cs:398

        /// <typeparam name="TState">The type of the state used in the generator loop.</typeparam>
        /// <typeparam name="TResult">The type of the elements in the produced sequence.</typeparam>
        /// <param name="initialState">Initial state.</param>
        /// <param name="condition">Condition to terminate generation (upon returning false).</param>
        /// <param name="iterate">Iteration step function.</param>
        /// <param name="resultSelector">Selector function for results produced in the sequence.</param>
        /// <param name="scheduler">Scheduler on which to run the generator loop.</param>
        /// <returns>The generated sequence.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="condition"/> or <paramref name="iterate"/> or <paramref name="resultSelector"/> or <paramref name="scheduler"/> is null.</exception>
        public static IObservable<TResult> Generate<TState, TResult>(TState initialState, Func<TState, bool> condition, Func<TState, TState> iterate, Func<TState, TResult> resultSelector, IScheduler scheduler)
        {
            if (condition == null)
            {
                throw new ArgumentNullException(nameof(condition));
            }

            if (iterate == null)
            {
                throw new ArgumentNullException(nameof(iterate));
            }

            if (resultSelector == null)
            {
                throw new ArgumentNullException(nameof(resultSelector));
            }

            if (scheduler == null)
            {
                throw new ArgumentNullException(nameof(scheduler));
            }

            return s_impl.Generate(initialState, condition, iterate, resultSelector, scheduler);
        }

        #endregion

        #region + Never +

View on GitHub (pinned to 94b5d5ab91)