dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'disposable')
Error message
Value cannot be null. (Parameter 'disposable')
What it means
The ContextDisposable constructor throws ArgumentNullException when the disposable argument is null. The wrapped IDisposable is the action payload whose Dispose runs on the provided SynchronizationContext; a null wrapped resource cannot be dispatched. The constructor validates both parameters with ?? throw.
Solutions
- Check the resource for null before constructing; skip creation when null.
- Substitute Disposable.Empty when a no-op disposable is acceptable: new ContextDisposable(ctx, Disposable.Empty).
- Fix the resource factory so it throws a meaningful error instead of returning null.
Example fix
// before var d = new ContextDisposable(ctx, AcquireResource()); // may return null // after var resource = AcquireResource(); var d = resource != null ? new ContextDisposable(ctx, resource) : null;
Defensive patterns
Strategy: validation
Validate before calling
if (resource == null) return null; // or use Disposable.Empty var d = new ContextDisposable(context, resource);
Type guard
ContextDisposable TryCreate(SynchronizationContext ctx, IDisposable d) => ctx == null || d == null ? null : new ContextDisposable(ctx, d);
Try / catch
try { var d = new ContextDisposable(context, resource); } catch (ArgumentNullException ex) when (ex.ParamName == "disposable") { /* handle missing resource */ } Prevention
- Treat factory methods returning null as failures before wrapping
- Substitute Disposable.Empty for optional resources
- Validate acquisition results before constructing wrappers
When it happens
Trigger: new ContextDisposable(ctx, null), usually when the wrapped resource comes from a factory/lookup that returned null (failed acquisition of a stream, subscription, or handle).
Common situations: Wrapping resources obtained from methods that return null on failure instead of throwing; conditional resource creation where the null path was not handled before constructing the ContextDisposable.
Related errors
- Value cannot be null. (Parameter 'onNextAsync')
- Value cannot be null. (Parameter 'onErrorAsync')
- Value cannot be null. (Parameter 'onCompletedAsync')
- Value cannot be null. (Parameter 'context')
- Value cannot be null. (Parameter 'dispose')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/0e3ec230f052cac9.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Disposables/ContextDisposable.cs:26
namespace System.Reactive.Disposables
{
/// <summary>
/// Represents a disposable resource whose disposal invocation will be posted to the specified <seealso cref="SynchronizationContext"/>.
/// </summary>
public sealed class ContextDisposable : ICancelable
{
private volatile IDisposable _disposable;
/// <summary>
/// Initializes a new instance of the <see cref="ContextDisposable"/> class that uses the specified <see cref="SynchronizationContext"/> on which to dispose the specified disposable resource.
/// </summary>
/// <param name="context">Context to perform disposal on.</param>
/// <param name="disposable">Disposable whose Dispose operation to run on the given synchronization context.</param>
/// <exception cref="ArgumentNullException"><paramref name="context"/> or <paramref name="disposable"/> is null.</exception>
public ContextDisposable(SynchronizationContext context, IDisposable disposable)
{
Context = context ?? throw new ArgumentNullException(nameof(context));
_disposable = disposable ?? throw new ArgumentNullException(nameof(disposable));
}
/// <summary>
/// Gets the provided <see cref="SynchronizationContext"/>.
/// </summary>
public SynchronizationContext Context { get; }
/// <summary>
/// Gets a value that indicates whether the object is disposed.
/// </summary>
public bool IsDisposed => _disposable == BooleanDisposable.True;
/// <summary>
/// Disposes the underlying disposable on the provided <see cref="SynchronizationContext"/>.
/// </summary>
public void Dispose()
{
var old = Interlocked.Exchange(ref _disposable, BooleanDisposable.True);View on GitHub (pinned to 94b5d5ab91)