dotnet/reactive · error · ArgumentNullException

ArgumentNullException

Error message

ArgumentNullException

What it means

The Timer(TimeSpan, IAsyncScheduler) factory throws ArgumentNullException because the 'scheduler' parameter was null. Timer needs a scheduler to schedule the single emission at dueTime; the library validates this before creating the observable.

Solutions

  1. Pass TaskPoolAsyncScheduler.Default as the scheduler.
  2. If the scheduler comes from DI/configuration, verify registration and null-check it before calling Timer.
  3. Use the parameterless-scheduler overload Timer(TimeSpan dueTime), which defaults the scheduler internally.

Example fix

// before
var timer = AsyncObservable.Timer(TimeSpan.FromSeconds(1), scheduler); // scheduler null from DI
// after
var timer = AsyncObservable.Timer(TimeSpan.FromSeconds(1), scheduler ?? TaskPoolAsyncScheduler.Default);
Defensive patterns

Strategy: validation

Validate before calling

if (scheduler is null) throw new ArgumentNullException(nameof(scheduler));
var timer = AsyncObservable.Timer(dueTime, scheduler);

Type guard

bool HasScheduler(IAsyncScheduler s) => s is not null;

Try / catch

try
{
    var timer = AsyncObservable.Timer(dueTime, scheduler);
}
catch (ArgumentNullException ex) when (ex.ParamName == "scheduler")
{
    var timer = AsyncObservable.Timer(dueTime); // default scheduler
}

Prevention

When it happens

Trigger: Calling AsyncObservable.Timer(dueTime, null) — e.g. a scheduler resolved from configuration or DI that is null, or a variable shadowing the intended scheduler.

Common situations: DI container failing to register an IAsyncScheduler implementation so the injected value is null; passing TimeSpan in the scheduler slot by mistake (overload argument-order mix-up).

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/Timer.cs:20

// 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.Threading.Tasks;

namespace System.Reactive.Linq
{
    public partial class AsyncObservable
    {
        public static IAsyncObservable<long> Timer(TimeSpan dueTime)
        {
            return Create<long>(observer => AsyncObserver.Timer(observer, dueTime));
        }

        public static IAsyncObservable<long> Timer(TimeSpan dueTime, IAsyncScheduler scheduler)
        {
            if (scheduler == null)
                throw new ArgumentNullException(nameof(scheduler));

            return Create<long>(observer => AsyncObserver.Timer(observer, dueTime, scheduler));
        }

        public static IAsyncObservable<long> Timer(DateTimeOffset dueTime)
        {
            return Create<long>(observer => AsyncObserver.Timer(observer, dueTime));
        }

        public static IAsyncObservable<long> Timer(DateTimeOffset dueTime, IAsyncScheduler scheduler)
        {
            if (scheduler == null)
                throw new ArgumentNullException(nameof(scheduler));

            return Create<long>(observer => AsyncObserver.Timer(observer, dueTime, scheduler));
        }

        public static IAsyncObservable<long> Timer(TimeSpan dueTime, TimeSpan period)

View on GitHub (pinned to 94b5d5ab91)