dotnet/reactive · error · ArgumentNullException

predicate

Error message

predicate

What it means

The predicate overload of SingleOrDefault throws ArgumentNullException when the Func<TSource,bool> predicate is null. The library validates arguments up front so the failure is synchronous and points at the exact argument.

Solutions

  1. Ensure a valid predicate delegate is supplied, e.g. x => true to match all elements.
  2. If the filter is optional, branch: call the parameterless SingleOrDefault(source) overload when no predicate exists.

Example fix

// before
Func<int, bool> pred = GetPredicate(); // may be null
var q = source.SingleOrDefault(pred);
// after
var q = pred != null ? source.SingleOrDefault(pred) : source.SingleOrDefault();
Defensive patterns

Strategy: validation

Validate before calling

if (source == null) throw new ArgumentNullException(nameof(source));
if (predicate == null) throw new ArgumentNullException(nameof(predicate));
var q = source.SingleOrDefault(predicate);

Type guard

static bool IsValidPredicate<T>(Func<T, bool> p) => p != null;

Try / catch

try { var v = await source.SingleOrDefaultAsync(pred); }
catch (ArgumentNullException ex) when (ex.ParamName == "predicate") { pred = _ => true; }

Prevention

When it happens

Trigger: Calling AsyncObservable.SingleOrDefault(source, null) — e.g. a predicate stored in a variable that was never assigned, or a lambda passed through an intermediate API that returned null.

Common situations: Conditional predicate building where an empty filter list yields a null delegate; passing a method group on a null object; deserialized configuration producing a null delegate.

Related errors


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

Appendix: source

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

    {
        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)
        {
            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)));

View on GitHub (pinned to 94b5d5ab91)