dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'handlers')

Error message

Value cannot be null. (Parameter 'handlers')

What it means

AsyncObserver.Concat<TSource>(observer, handlers) throws ArgumentNullException naming 'handlers' when the IEnumerator<IAsyncObservable<TSource>> is null. The enumerator supplies the sequences to be concatenated, so it cannot be null (an empty enumerator is fine).

Solutions

  1. Pass a non-null IEnumerator<IAsyncObservable<TSource>>
  2. Guard the source collection first: if (list == null) use an empty list's enumerator
  3. Default to an empty enumerator to mean 'concatenate nothing' rather than null

Example fix

// before
var (sink, disp) = AsyncObserver.Concat(observer, sources.GetEnumerator()); // sources is null
// after
var enumerator = (sources ?? new List<IAsyncObservable<int>>()).GetEnumerator();
var (sink, disp) = AsyncObserver.Concat(observer, enumerator);
Defensive patterns

Strategy: validation

Validate before calling

if (handlers is null) handlers = (Enumerable.Empty<IAsyncObservable<TSource>>()).GetEnumerator();

Type guard

public static bool HasHandlers<T>(IEnumerator<IAsyncObservable<T>>? e) => e is not null;

Try / catch

try { var (sink, disp) = AsyncObserver.Concat(observer, handlers); }
catch (ArgumentNullException ex) when (ex.ParamName == "handlers") { /* use an empty enumerator */ }

Prevention

When it happens

Trigger: Calling AsyncObserver.Concat(observer, null), e.g. passing result of a method that returned null instead of an enumerator, or passing the enumerator of a null collection.

Common situations: Dynamic source lists from config/DI where obtaining the enumerator happened on a null collection; mapping null lists to enumerators without a null check.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Concat.cs:92

                observer.OnNextAsync,
                observer.OnErrorAsync,
                async () =>
                {
                    var secondSubscription = await second.SubscribeSafeAsync(observer).ConfigureAwait(false);

                    await subscription.AssignAsync(secondSubscription).ConfigureAwait(false);
                }
            );

            return (sink, subscription);
        }

        public static (IAsyncObserver<TSource>, IAsyncDisposable) Concat<TSource>(IAsyncObserver<TSource> observer, IEnumerator<IAsyncObservable<TSource>> handlers)
        {
            if (observer == null)
                throw new ArgumentNullException(nameof(observer));
            if (handlers == null)
                throw new ArgumentNullException(nameof(handlers));

            var innerSubscription = new SerialAsyncDisposable();

            IAsyncObserver<TSource> GetSink() =>
                Create<TSource>(
                    observer.OnNextAsync,
                    observer.OnErrorAsync,
                    async () =>
                    {
                        var next = default(IAsyncObservable<TSource>);

                        try
                        {
                            if (handlers.MoveNext())
                            {
                                next = handlers.Current;
                            }
                        }

View on GitHub (pinned to 94b5d5ab91)