dotnet/reactive · error · ArgumentNullException

source

Error message

source

What it means

Thrown by SingleOrDefault(source) when the source IAsyncObservable is null. SingleOrDefault differs from Single only in tolerating empty sequences, not null arguments — null source is still an immediate ArgumentNullException. The library's convention is eager validation in every public operator.

Solutions

  1. Verify the source is non-null before calling SingleOrDefault
  2. Substitute AsyncObservable.Empty<TSource>() when a null source should mean 'no elements'
  3. Find the upstream producer returning null and fix it there

Example fix

// before
var single = await source.SingleOrDefaultAsync();
// after
var single = await (source ?? AsyncObservable.Empty<int>()).SingleOrDefaultAsync();
Defensive patterns

Strategy: validation

Validate before calling

if (source is null) source = AsyncObservable.Empty<T>();

Type guard

static bool IsQueryable<T>(IAsyncObservable<T>? s) => s is not null;

Try / catch

try { var v = await source.SingleOrDefaultAsync(); }
catch (ArgumentNullException ex) when (ex.ParamName == "source") { /* treat as empty sequence */ }

Prevention

When it happens

Trigger: Calling SingleOrDefaultAsync(source) or SingleOrDefault(source) with a null source observable.

Common situations: Observables obtained from caches, dictionaries, or DI that can be null; chained queries where an upstream factory returned null.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/SingleOrDefault.cs:18

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT License.
// See the LICENSE file in the project root for more information. 

using System.Threading.Tasks;

namespace System.Reactive.Linq
{
    public partial class AsyncObservable
    {
        public static IAsyncObservable<TSource> SingleOrDefaultAsync<TSource>(this IAsyncObservable<TSource> source) => SingleOrDefault(source);
        public static IAsyncObservable<TSource> SingleOrDefaultAsync<TSource>(this IAsyncObservable<TSource> source, Func<TSource, bool> predicate) => SingleOrDefault(source, predicate);
        public static IAsyncObservable<TSource> SingleOrDefaultAsync<TSource>(this IAsyncObservable<TSource> source, Func<TSource, ValueTask<bool>> predicate) => SingleOrDefault(source, predicate);

        public static IAsyncObservable<TSource> SingleOrDefault<TSource>(this IAsyncObservable<TSource> source)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));

            return Create(source, static (source, observer) => source.SubscribeSafeAsync(AsyncObserver.SingleOrDefault(observer)));
        }

        public static IAsyncObservable<TSource> SingleOrDefault<TSource>(this IAsyncObservable<TSource> source, Func<TSource, bool> predicate)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (predicate == null)
                throw new ArgumentNullException(nameof(predicate));

            return CreateAsyncObservable<TSource>.From(
                source,
                predicate,
                static (source, predicate, observer) => source.SubscribeSafeAsync(AsyncObserver.SingleOrDefault(observer, predicate)));
        }

        public static IAsyncObservable<TSource> SingleOrDefault<TSource>(this IAsyncObservable<TSource> source, Func<TSource, ValueTask<bool>> predicate)

View on GitHub (pinned to 94b5d5ab91)