dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'disposable1')

Error message

Value cannot be null. (Parameter 'disposable1')

What it means

StableCompositeAsyncDisposable.Create(disposable1, disposable2) validates both disposables before building a Binary composite. This library throws ArgumentNullException for null arguments to fail fast instead of throwing later during DisposeAsync. The first parameter was null.

Solutions

  1. Pass a non-null IAsyncDisposable as the first argument (e.g. NoopAsyncDisposable or a real resource).
  2. Check the code producing disposable1 for null-returning factory calls and handle that null there.
  3. If one side may be absent, guard with a conditional before composing, or filter nulls from your disposal list and use the params Create overload.

Example fix

// before
var composite = StableCompositeAsyncDisposable.Create(GetClient(), subscription);
// after
var client = GetClient() ?? throw new InvalidOperationException("client not initialized");
var composite = StableCompositeAsyncDisposable.Create(client, subscription);
Defensive patterns

Strategy: validation

Validate before calling

if (disposable1 is null) throw new ArgumentNullException(nameof(disposable1));
var composite = StableCompositeAsyncDisposable.Create(disposable1, disposable2);

Type guard

static bool IsDisposable(IAsyncDisposable? d) => d is not null;

Try / catch

try { var c = StableCompositeAsyncDisposable.Create(d1, d2); }
catch (ArgumentNullException ex) when (ex.ParamName == "disposable1")
{ log.LogWarning("disposable1 was null"); }

Prevention

When it happens

Trigger: Calling StableCompositeAsyncDisposable.Create(null, someDisposable) with a null first IAsyncDisposable, typically because an upstream factory or field returned null.

Common situations: Wiring up two resources where one failed to initialize (e.g. a cancelled connection returned null); refactors that change disposal ownership leaving one field unset; conditional resource creation paths that skip assignment.

Related errors


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/Disposables/StableCompositeAsyncDisposable.cs:16

// 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.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace System.Reactive.Disposables
{
    public abstract class StableCompositeAsyncDisposable : IAsyncDisposable
    {
        public static StableCompositeAsyncDisposable Create(IAsyncDisposable disposable1, IAsyncDisposable disposable2)
        {
            if (disposable1 == null)
                throw new ArgumentNullException(nameof(disposable1));
            if (disposable2 == null)
                throw new ArgumentNullException(nameof(disposable2));

            return new Binary(disposable1, disposable2);
        }

        public static StableCompositeAsyncDisposable Create(params IAsyncDisposable[] disposables)
        {
            if (disposables == null)
                throw new ArgumentNullException(nameof(disposables));

            return new NAry(disposables);
        }

        public static StableCompositeAsyncDisposable Create(IEnumerable<IAsyncDisposable> disposables)
        {
            if (disposables == null)
                throw new ArgumentNullException(nameof(disposables));

View on GitHub (pinned to 94b5d5ab91)