dotnet/reactive · error · ArgumentNullException

new ArgumentNullException(nameof(iterate))

Error message

new ArgumentNullException(nameof(iterate))

What it means

AsyncReactive's Generate operator throws ArgumentNullException when the iterate (state-advance) delegate is null. Generate requires every per-iteration callback (condition, iterate, resultSelector, timeSelector) to advance/emit values; a null iterate would make the state machine unable to progress past the first element, so it is rejected eagerly before scheduling.

Solutions

  1. Pass a non-null iterate delegate, e.g. s => new ValueTask<TState>(s + 1) or an equivalent method group.
  2. If iterate is optional in your design, supply an identity function s => new ValueTask<TState>(s) instead of null.
  3. Check the expression producing the delegate (ternary, config-driven lookup) and guard it before calling Generate.

Example fix

// before
Func<int, ValueTask<int>> iterate = maybeStep; // null
await AsyncObservable.Generate(observer, 0, s => new ValueTask<bool>(s < 10), iterate, ...);
// after
var iterate = maybeStep ?? (s => new ValueTask<int>(s + 1));
await AsyncObservable.Generate(observer, 0, s => new ValueTask<bool>(s < 10), iterate, ...);
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

static bool IsValidGenerateArgs<TState, TResult>(Func<TState, ValueTask<bool>> cond, Func<TState, ValueTask<TState>> iter, Func<TState, ValueTask<TResult>> sel, Func<TState, ValueTask<TimeSpan>> time, IAsyncScheduler sched) => cond != null && iter != null && sel != null && time != null && sched != null;

Try / catch

try { var d = await Generate(observer, 0, cond, iter, sel, timeSel, sched); } catch (ArgumentNullException ex) { /* ex.ParamName == "iterate" */ }

Prevention

When it happens

Trigger: Calling the fully-async overload AsyncRx.NET/System.Reactive.Async/Linq/Operators/Generate.cs:345 (Generate(observer, initialState, condition, iterate, resultSelector, timeSelector, scheduler) with ValueTask-returning delegates) passing null for the Func<TState, ValueTask<TState>> iterate parameter, typically via a ternary or variable that resolves to null.

Common situations: Building a timed generator where the iterate lambda is conditionally assigned; passing a method group whose target is null; refactoring from Rx's Generate where iterate was optional or inferred and porting to System.Reactive.Async where it is mandatory.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Generate.cs:352

                throw new ArgumentNullException(nameof(condition));
            if (iterate == null)
                throw new ArgumentNullException(nameof(iterate));
            if (resultSelector == null)
                throw new ArgumentNullException(nameof(resultSelector));
            if (timeSelector == null)
                throw new ArgumentNullException(nameof(timeSelector));

            return Generate(observer, initialState, condition, iterate, resultSelector, timeSelector, TaskPoolAsyncScheduler.Default);
        }

        public static ValueTask<IAsyncDisposable> Generate<TState, TResult>(IAsyncObserver<TResult> observer, TState initialState, Func<TState, ValueTask<bool>> condition, Func<TState, ValueTask<TState>> iterate, Func<TState, ValueTask<TResult>> resultSelector, Func<TState, ValueTask<TimeSpan>> timeSelector, IAsyncScheduler scheduler)
        {
            if (observer == null)
                throw new ArgumentNullException(nameof(observer));
            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 (timeSelector == null)
                throw new ArgumentNullException(nameof(timeSelector));
            if (scheduler == null)
                throw new ArgumentNullException(nameof(scheduler));

            return scheduler.ScheduleAsync(async ct =>
            {
                var first = true;
                var state = initialState;

                while (!ct.IsCancellationRequested)
                {
                    var hasResult = false;
                    var result = default(TResult);
                    var nextDue = default(TimeSpan);

View on GitHub (pinned to 94b5d5ab91)