dotnet/reactive · error · ArgumentNullException

ArgumentNullException

Error message

ArgumentNullException

What it means

The Timeout operator shifts to an error/completion if the source produces no notification within dueTime, and it requires a non-null source observable. If source is null the operator cannot subscribe, so it throws ArgumentNullException at composition time, before any timer is scheduled.

Solutions

  1. Ensure the source observable is non-null before applying Timeout
  2. Guard with a null check or substitute AsyncObservable.Never<TSource>()/Empty<TSource>() for a null source
  3. Trace the upstream composition to find where null originated

Example fix

// before
var withTimeout = source.Timeout(TimeSpan.FromSeconds(5)); // source null
// after
var withTimeout = (source ?? AsyncObservable.Never<int>()).Timeout(TimeSpan.FromSeconds(5));
Defensive patterns

Strategy: validation

Validate before calling

if (source is null) throw new InvalidOperationException("source observable not initialized");
var withTimeout = source.Timeout(TimeSpan.FromSeconds(5));

Type guard

bool IsSubscribable<TSource>(IAsyncObservable<TSource>? s) => s is not null;

Try / catch

try
{
    withTimeout = source.Timeout(TimeSpan.FromSeconds(5));
}
catch (ArgumentNullException ex) when (ex.ParamName == "source")
{
    withTimeout = AsyncObservable.Never<int>(); // or surface configuration error
}

Prevention

When it happens

Trigger: Calling source.Timeout(dueTime) where source == null — e.g. a null returned by an upstream factory, failed DI resolution, or a nullable variable not checked before chaining.

Common situations: Long operator chains where an early operator returned null; conditional pipeline construction missing an assignment; tests that forget to instantiate the observable under timeout behavior.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Timeout.cs:17

// 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.Reactive.Concurrency;
using System.Reactive.Disposables;
using System.Threading;
using System.Threading.Tasks;

namespace System.Reactive.Linq
{
    public partial class AsyncObservable
    {
        public static IAsyncObservable<TSource> Timeout<TSource>(this IAsyncObservable<TSource> source, TimeSpan dueTime)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));

            return CreateAsyncObservable<TSource>.From(
                source,
                dueTime,
                static async (source, dueTime, observer) =>
                {
                    var sourceSubscription = new SingleAssignmentAsyncDisposable();

                    var (sink, disposable) = await AsyncObserver.Timeout(observer, sourceSubscription, dueTime).ConfigureAwait(false);

                    var sourceSubscriptionInner = await source.SubscribeSafeAsync(sink).ConfigureAwait(false);

                    await sourceSubscription.AssignAsync(sourceSubscriptionInner).ConfigureAwait(false);

                    return disposable;
                });
        }

View on GitHub (pinned to 94b5d5ab91)