dotnet/reactive · error · ArgumentNullException

predicate

Error message

predicate

What it means

This Last overload takes a predicate to filter which elements qualify as candidates for the last element; a null predicate is rejected because the filter would be undefined. The guard runs in Last, which the LastAsync overloads forward to. Fix: pass a non-null Func<TSource, bool>, or use the parameterless Last(source).

Solutions

  1. Pass a valid predicate lambda, e.g. x => true if no filtering is intended.
  2. Null-check or default the predicate before calling Last: predicate ?? (_ => true).
  3. Use the parameterless Last overload when no filtering is needed.

Example fix

// before
var last = source.Last(filter); // filter is null
// after
var last = filter == null ? source.Last() : source.Last(filter);
Defensive patterns

Strategy: validation

Validate before calling

if (predicate is null) predicate = static _ => true;
var last = await source.Last(predicate);

Type guard

static bool HasPredicate<T>(Func<T, bool>? p) => p is not null;

Try / catch

try { var last = await source.Last(predicate); }
catch (ArgumentNullException ex) when (ex.ParamName == "predicate") { last = await source.Last(); }

Prevention

When it happens

Trigger: Calling source.Last(null) or passing a predicate variable that was never assigned (e.g. an optional filter parameter defaulting to null).

Common situations: Optional filter delegates passed as null from configuration-driven code; refactoring removed a lambda but left the call; an API boundary forwards a caller-supplied null delegate.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Last.cs:30

        public static IAsyncObservable<TSource> LastAsync<TSource>(this IAsyncObservable<TSource> source, Func<TSource, bool> predicate) => Last(source, predicate);
        public static IAsyncObservable<TSource> LastAsync<TSource>(this IAsyncObservable<TSource> source, Func<TSource, ValueTask<bool>> predicate) => Last(source, predicate);

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

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

        public static IAsyncObservable<TSource> Last<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.Last(observer, predicate)));
        }

        public static IAsyncObservable<TSource> Last<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.Last(observer, predicate)));

View on GitHub (pinned to 94b5d5ab91)