dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'disposable')
Error message
Value cannot be null. (Parameter 'disposable')
What it means
ScheduledDisposable's constructor requires a non-null IDisposable resource; the value is stored in a SingleAssignmentDisposable and null is rejected with ArgumentNullException. Both constructor parameters are individually validated, so this fires only when the second argument is null.
Solutions
- Ensure the resource to dispose is created before constructing ScheduledDisposable.
- Use Disposable.Empty as a non-null placeholder when there is nothing to dispose.
- Null-check the resource first and skip creating the ScheduledDisposable if absent.
Example fix
// before var sd = new ScheduledDisposable(scheduler, AcquireResource()); // may be null // after var resource = AcquireResource() ?? Disposable.Empty; var sd = new ScheduledDisposable(scheduler, resource);
Defensive patterns
Strategy: validation
Validate before calling
if (resource is null) resource = Disposable.Empty; var sd = new ScheduledDisposable(scheduler, resource);
Type guard
static bool HasResource(IDisposable d) => d is not null;
Try / catch
try { var sd = new ScheduledDisposable(scheduler, resource); }
catch (ArgumentNullException ex) when (ex.ParamName == "disposable") { /* substitute Disposable.Empty and retry */ } Prevention
- Coalesce nullable acquisition results with Disposable.Empty before wrapping.
- Keep resource-acquisition methods non-null-returning (return Empty for 'nothing to do').
- Test code paths where the wrapped resource may be absent.
When it happens
Trigger: Calling new ScheduledDisposable(scheduler, null) — passing null for the 'disposable' parameter, typically when the wrapped resource comes from a factory or optional lookup that returned null.
Common situations: Wrapping the result of a GetResource()/TryGetValue pattern that can return null, or a conditional resource acquisition where one branch never assigns the disposable.
Related errors
- Value cannot be null. (Parameter 'disposable')
- Value cannot be null. (Parameter 'scheduler')
- Value cannot be null. (Parameter 'disposable1')
- Value cannot be null. (Parameter 'disposable2')
- Value cannot be null. (Parameter 'disposables')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/09b6785e06b56968.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Disposables/ScheduledDisposable.cs:25
namespace System.Reactive.Disposables
{
/// <summary>
/// Represents a disposable resource whose disposal invocation will be scheduled on the specified <seealso cref="IScheduler"/>.
/// </summary>
public sealed class ScheduledDisposable : ICancelable
{
private SingleAssignmentDisposableValue _disposable;
/// <summary>
/// Initializes a new instance of the <see cref="ScheduledDisposable"/> class that uses an <see cref="IScheduler"/> on which to dispose the disposable.
/// </summary>
/// <param name="scheduler">Scheduler where the disposable resource will be disposed on.</param>
/// <param name="disposable">Disposable resource to dispose on the given scheduler.</param>
/// <exception cref="ArgumentNullException"><paramref name="scheduler"/> or <paramref name="disposable"/> is null.</exception>
public ScheduledDisposable(IScheduler scheduler, IDisposable disposable)
{
Scheduler = scheduler ?? throw new ArgumentNullException(nameof(scheduler));
_disposable.Disposable = disposable ?? throw new ArgumentNullException(nameof(disposable));
}
/// <summary>
/// Gets the scheduler where the disposable resource will be disposed on.
/// </summary>
public IScheduler Scheduler { get; }
/// <summary>
/// Gets the underlying disposable. After disposal, the result is undefined.
/// </summary>
public IDisposable Disposable => _disposable.Disposable ?? Disposables.Disposable.Empty;
/// <summary>
/// Gets a value that indicates whether the object is disposed.
/// </summary>
public bool IsDisposed => _disposable.IsDisposed;
/// <summary>View on GitHub (pinned to 94b5d5ab91)