dotnet/reactive · error · ArgumentNullException

source

Error message

source

What it means

The Last operator throws ArgumentNullException because the source IAsyncObservable<TSource> was null. Last emits the final element (optionally matching a predicate) of a sequence; a null source has no elements to observe, so the library fails fast at operator creation. Called via LastAsync/Last extension methods.

Solutions

  1. Pass a non-null IAsyncObservable<TSource> to Last/LastAsync.
  2. If the source may be absent, use AsyncObservable.Empty<TSource>() so Last surfaces an empty-sequence error through normal semantics instead.
  3. Trace and fix the upstream producer that returned null instead of a valid observable.

Example fix

// before
var last = await maybeSource!.Last().FirstOrDefaultAsync();
// after
var src = maybeSource ?? AsyncObservable.Empty<TSource>();
var last = await src.Last().FirstOrDefaultAsync();
Defensive patterns

Strategy: validation

Validate before calling

if (source is null) throw new ArgumentException("source observable must be non-null before calling Last", nameof(source));

Type guard

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

Try / catch

try { var last = await source.Last(); }
catch (ArgumentNullException ex) when (ex.ParamName == "source") { /* fix the null producer or fall back to an empty observable */ }

Prevention

When it happens

Trigger: Calling source.Last() or source.LastAsync(predicate) where source is null — e.g. a repository method returned null instead of an empty observable, or a nullable field was never assigned.

Common situations: Chaining off a factory method that returns null on failure, conditional pipeline assembly where an upstream step was skipped, or dictionary/config lookups missing a key.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Last.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> LastAsync<TSource>(this IAsyncObservable<TSource> source) => Last(source);
        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)));
        }

View on GitHub (pinned to 94b5d5ab91)