dotnet/reactive · error · ArgumentException

Strings_Core.DISPOSABLES_CANT_CONTAIN_NULL

Error message

Strings_Core.DISPOSABLES_CANT_CONTAIN_NULL

What it means

StableCompositeDisposable.Create(...) validates its collection of disposables before accepting them. If the passed enumerable contains a null element, an ArgumentException with DISPOSABLES_CANT_CONTAIN_NULL is thrown from the NAryEnumerable constructor. StableCompositeDisposable requires all elements to be non-null so Dispose can iterate and dispose every item without null checks.

Solutions

  1. Filter out nulls before passing: pass disposables.Where(d => d != null).
  2. Fix the code constructing the collection so it never produces null entries.
  3. Assert or log collection contents during construction to locate the null source.

Example fix

// before
var composite = StableCompositeDisposable.Create(disposables);
// after
var composite = StableCompositeDisposable.Create(disposables.Where(d => d != null));
Defensive patterns

Strategy: validation

Validate before calling

if (disposables == null) throw new ArgumentNullException(nameof(disposables));
if (disposables.Any(d => d == null)) throw new ArgumentException("collection contains null", nameof(disposables));

Type guard

bool AllNonNull(IEnumerable<IDisposable?> xs) => xs != null && !xs.Any(d => d is null);

Try / catch

try { var c = StableCompositeDisposable.Create(disposables); } catch (ArgumentException ex) when (ex.ParamName == nameof(disposables)) { /* sanitize collection and retry */ }

Prevention

When it happens

Trigger: Calling StableCompositeDisposable.Create(IEnumerable<IDisposable>) (the NAryEnumerable path) where the enumerable yields a null element, e.g. a List<IDisposable> with a null entry or a LINQ projection producing nulls.

Common situations: Building the collection from external or config-driven input where some entries failed to initialize; conditional assignment patterns like cond ? d : null; deserialized collections containing nulls.

Related errors


AI-assisted analysis of dotnet/reactive@94b5d5ab91 (2026-09-15). Data as JSON: /api/errors/2d153e0ac75d6eba. Report an issue: GitHub.

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Disposables/StableCompositeDisposable.cs:125

                _disposable1.Dispose();
                _disposable2.Dispose();
            }
        }

        private sealed class NAryEnumerable : StableCompositeDisposable
        {
            private volatile List<IDisposable>? _disposables;

            public NAryEnumerable(IEnumerable<IDisposable> disposables)
            {
                _disposables = new List<IDisposable>(disposables);

                //
                // Doing this on the list to avoid duplicate enumeration of disposables.
                //
                if (_disposables.Contains(null!))
                {
                    throw new ArgumentException(Strings_Core.DISPOSABLES_CANT_CONTAIN_NULL, nameof(disposables));
                }
            }

            public override bool IsDisposed => _disposables == null;

            public override void Dispose()
            {
                var old = Interlocked.Exchange(ref _disposables, null);
                if (old != null)
                {
                    foreach (var d in old)
                    {
                        d.Dispose();
                    }
                }
            }
        }

View on GitHub (pinned to 94b5d5ab91)