dotnet/reactive · error · ArgumentNullException
Value cannot be null. (Parameter 'item')
Error message
Value cannot be null. (Parameter 'item')
What it means
CompositeDisposable.Add requires a non-null IDisposable; a null item has no Dispose behavior and would break Remove/Dispose bookkeeping, so ArgumentNullException with parameter name 'item' is thrown before the lock is taken. Callers listed (Subscribe, DisposeWith, Run, etc.) are typical upstream paths where a null disposable flows in.
Solutions
- Never return null from helper methods that produce disposables — return Disposable.Empty instead
- Check for null before adding: if (d != null) composite.Add(d);
- Ensure your ISubscribe-like implementations follow the Rx contract of returning a non-null IDisposable
Example fix
// before composite.Add(SubscribeToSomething()); // may return null // after var d = SubscribeToSomething(); if (d != null) composite.Add(d);
Defensive patterns
Strategy: type-guard
Validate before calling
if (item != null) composite.Add(item);
Type guard
void AddSafe(CompositeDisposable cd, IDisposable? item) { if (item is not null) cd.Add(item); } Try / catch
try { composite.Add(d); }
catch (ArgumentNullException) { /* log: subscription returned null disposable */ } Prevention
- Return Disposable.Empty instead of null from subscribe-like helpers
- Use the is not null pattern at call sites
- Centralize Add behind a helper that null-checks
- Follow the Rx contract: Subscribe must return a non-null IDisposable
When it happens
Trigger: composite.Add(null), or passing the result of a Subscribe/handler-registration helper that returned null (e.g. a hand-rolled Subscribe returning null instead of Disposable.Empty).
Common situations: Manual subscription management where teardown registration methods return null on failure; conditional code paths assigning null to a disposable variable; interop with other libraries returning null tokens.
Related errors
- Value cannot be null. (Parameter 'cts')
- Value cannot be null. (Parameter 'disposables')
- Value cannot be null. (Parameter 'observer')
- Value cannot be null. (Parameter 'observableFactory')
- observableFactory
AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15).
Data as JSON: /api/errors/ec2ac4179696668a.
Report an issue: GitHub.
Appendix: source
Thrown at Rx.NET/Source/src/System.Reactive/Disposables/CompositeDisposable.cs:165
return (list, list.Count);
}
/// <summary>
/// Gets the number of disposables contained in the <see cref="CompositeDisposable"/>.
/// </summary>
public int Count => Volatile.Read(ref _count);
/// <summary>
/// Adds a disposable to the <see cref="CompositeDisposable"/> or disposes the disposable if the <see cref="CompositeDisposable"/> is disposed.
/// </summary>
/// <param name="item">Disposable to add.</param>
/// <exception cref="ArgumentNullException"><paramref name="item"/> is <c>null</c>.</exception>
public void Add(IDisposable item)
{
if (item == null)
{
throw new ArgumentNullException(nameof(item));
}
lock (_gate)
{
if (!_disposed)
{
if (_disposables is List<IDisposable?> listDisposables)
{
listDisposables.Add(item);
// Once we get to thousands of items (which happens with wide fan-out/in configurations)
// the cost of linear search becomes too high. We switch to a dictionary at that point.
// See https://github.com/dotnet/reactive/issues/2005
if (listDisposables.Count > MaximumLinearSearchThreshold)
{
// If we've blown through this threshold, chances are there's more to come,
// so allocate some more spare capacity.
var dictionary = new Dictionary<IDisposable, int>(listDisposables.Count + (listDisposables.Count / 4));View on GitHub (pinned to 94b5d5ab91)