dotnet/reactive · error · ArgumentNullException
source
Error message
source
What it means
Thrown by SingleOrDefault(source) when the source IAsyncObservable is null. SingleOrDefault differs from Single only in tolerating empty sequences, not null arguments — null source is still an immediate ArgumentNullException. The library's convention is eager validation in every public operator.
Solutions
- Verify the source is non-null before calling SingleOrDefault
- Substitute AsyncObservable.Empty<TSource>() when a null source should mean 'no elements'
- Find the upstream producer returning null and fix it there
Example fix
// before var single = await source.SingleOrDefaultAsync(); // after var single = await (source ?? AsyncObservable.Empty<int>()).SingleOrDefaultAsync();
Defensive patterns
Strategy: validation
Validate before calling
if (source is null) source = AsyncObservable.Empty<T>();
Type guard
static bool IsQueryable<T>(IAsyncObservable<T>? s) => s is not null;
Try / catch
try { var v = await source.SingleOrDefaultAsync(); }
catch (ArgumentNullException ex) when (ex.ParamName == "source") { /* treat as empty sequence */ } Prevention
- Treat null and empty as distinct: normalize null to Empty early
- Ensure repository/cache lookups return Empty observables, not null
- Enable nullable reference types to catch unassigned observable fields at compile time
When it happens
Trigger: Calling SingleOrDefaultAsync(source) or SingleOrDefault(source) with a null source observable.
Common situations: Observables obtained from caches, dictionaries, or DI that can be null; chained queries where an upstream factory returned null.
Related errors
- ArgumentNullException
- Value cannot be null. (Parameter 'clock')
- Value cannot be null. (Parameter 'source')
- Value cannot be null. (Parameter 'onCompletedAsync')
- Value cannot be null. (Parameter 'onNext')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/1e1350ef7ad5a67a.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Linq/Operators/SingleOrDefault.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> 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)View on GitHub (pinned to 94b5d5ab91)