dotnet/reactive · error · ArgumentNullException
source
Error message
source
What it means
The Sample<TSource>(IObservable<TSource>, TimeSpan) operator throws ArgumentNullException when the source observable is null. Rx operators validate all reference arguments eagerly at call time so a bad composition fails immediately at the call site instead of surfacing as a null reference when subscribing. This is a programmer error, not a runtime condition.
Solutions
- Ensure the source observable is assigned before calling Sample; trace where the null reference originates.
- Guard the call site: if (source == null) throw or substitute Observable.Empty<TSource>().
- Fix the producing code so it never returns null — return Observable.Empty<TSource>() instead.
Example fix
// before IObservable<int> src = GetStream(); // may return null var sampled = src.Sample(TimeSpan.FromSeconds(1)); // ArgumentNullException // after var src = GetStream() ?? Observable.Empty<int>(); var sampled = src.Sample(TimeSpan.FromSeconds(1));
Defensive patterns
Strategy: validation
Validate before calling
if (source == null)
throw new ArgumentException("source must not be null before calling Sample");
if (interval < TimeSpan.Zero)
throw new ArgumentException("interval must be non-negative");
var sampled = source.Sample(interval); Type guard
static bool IsValidSampleInput<TSource>(IObservable<TSource> source, TimeSpan interval) =>
source != null && interval >= TimeSpan.Zero; Try / catch
try
{
var sampled = source.Sample(interval);
}
catch (ArgumentNullException) { /* source was null — fix producer */ }
catch (ArgumentOutOfRangeException) { /* negative interval */ } Prevention
- Never let factory methods return null observables — return Observable.Empty<T>().
- Initialize observable fields at construction, not lazily at use.
- Validate TimeSpan parameters at application boundaries before composing operators.
When it happens
Trigger: Calling Observable.Sample<TSource>(null, someTimeSpan) — i.e., the source argument is a null IObservable<TSource> reference, typically from an uninitialized field, a failed factory method, or a dictionary miss.
Common situations: Storing an IObservable in a field that was never assigned; a config-driven factory returning null; chaining LINQ-style operators where an earlier method returned null instead of an empty sequence; refactoring where a DI container failed to inject the observable.
Related errors
- Value cannot be null. (Parameter 'bufferOpenings')
- Value cannot be null. (Parameter 'bufferBoundaries')
- Value cannot be null. (Parameter 'handler')
- throw new ArgumentNullException(nameof(condition));
- sampler
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/572f6b1c32f4f153.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable.Time.cs:850
/// <summary>
/// Samples the observable sequence at each interval.
/// Upon each sampling tick, the latest element (if any) in the source sequence during the last sampling interval is sent to the resulting sequence.
/// </summary>
/// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
/// <param name="source">Source sequence to sample.</param>
/// <param name="interval">Interval at which to sample. If this value is equal to TimeSpan.Zero, the scheduler will continuously sample the stream.</param>
/// <returns>Sampled observable sequence.</returns>
/// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="interval"/> is less than TimeSpan.Zero.</exception>
/// <remarks>
/// Specifying a TimeSpan.Zero value for <paramref name="interval"/> doesn't guarantee all source sequence elements will be preserved. This is a side-effect
/// of the asynchrony introduced by the scheduler, where the sampling action may not execute immediately, despite the TimeSpan.Zero due time.
/// </remarks>
public static IObservable<TSource> Sample<TSource>(this IObservable<TSource> source, TimeSpan interval)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (interval < TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException(nameof(interval));
}
return s_impl.Sample(source, interval);
}
/// <summary>
/// Samples the observable sequence at each interval, using the specified scheduler to run sampling timers.
/// Upon each sampling tick, the latest element (if any) in the source sequence during the last sampling interval is sent to the resulting sequence.
/// </summary>
/// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
/// <param name="source">Source sequence to sample.</param>
/// <param name="interval">Interval at which to sample. If this value is equal to TimeSpan.Zero, the scheduler will continuously sample the stream.</param>
/// <param name="scheduler">Scheduler to run the sampling timer on.</param>View on GitHub (pinned to 94b5d5ab91)