dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'disposable')
Error message
Value cannot be null. (Parameter 'disposable')
What it means
The RefCountAsyncDisposable constructor throws ArgumentNullException when the underlying IAsyncDisposable is null. Reference-counting wrappers exist solely to share and ref-count a real disposable, so constructing one without a target is a programming error the library rejects eagerly.
Solutions
- Ensure the underlying disposable is created/assigned before constructing RefCountAsyncDisposable
- Add a null guard at the call site and fail fast with a clearer message
- If the disposable is conditionally available, defer creating the ref-count wrapper until it exists
Example fix
// before
var refCounted = new RefCountAsyncDisposable(_underlying); // _underlying is null
// after
if (_underlying == null)
throw new InvalidOperationException("Underlying disposable was not initialized.");
var refCounted = new RefCountAsyncDisposable(_underlying); Defensive patterns
Strategy: validation
Validate before calling
if (underlying is null)
throw new InvalidOperationException("Underlying disposable must be created before ref-counting it.");
var refCounted = new RefCountAsyncDisposable(underlying); Type guard
bool HasDisposable([NotNullWhen(true)] IAsyncDisposable? d) => d is not null;
Try / catch
try
{
var refCounted = new RefCountAsyncDisposable(underlying);
}
catch (ArgumentNullException ex) when (ex.ParamName == "disposable")
{
// underlying resource was never created; handle initialization failure here
} Prevention
- Create the underlying disposable in the same expression that builds the wrapper
- Avoid nullable disposable fields crossing into constructor calls unchecked
- Use a no-op disposable instead of null for 'nothing to dispose' cases
When it happens
Trigger: Passing a null IAsyncDisposable to 'new RefCountAsyncDisposable(...)' — typically when the base disposable came from an uninitialized field, a failed factory, or a nullable variable that was never assigned.
Common situations: Refactoring a nullable disposable into a non-null parameter; passing the result of an expression that returned null on a failure path; unit tests constructing the wrapper before the underlying resource exists.
Related errors
- Value cannot be null. (Parameter 'disposable')
- Value cannot be null. (Parameter 'disposable')
- keySelector
- Value cannot be null. (Parameter 'keySelector')
- Value cannot be null. (Parameter 'comparer')
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/27847835d0213397.
Report an issue: GitHub.
Appendix: source
Thrown at AsyncRx.NET/System.Reactive.Async/Disposables/RefCountAsyncDisposable.cs:19
// 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;
using System.Threading.Tasks;
namespace System.Reactive.Disposables
{
public sealed class RefCountAsyncDisposable : IAsyncDisposable
{
private readonly AsyncGate _gate = new();
private IAsyncDisposable _disposable;
private bool _primaryDisposed;
private int _count;
public RefCountAsyncDisposable(IAsyncDisposable disposable)
{
_disposable = disposable ?? throw new ArgumentNullException(nameof(disposable));
_primaryDisposed = false;
_count = 0;
}
public async ValueTask<IAsyncDisposable> GetDisposableAsync()
{
using (await _gate.LockAsync().ConfigureAwait(false))
{
if (_disposable == null)
{
return AsyncDisposable.Nop;
}
else
{
_count++;
return new Inner(this);
}
}View on GitHub (pinned to 94b5d5ab91)