{"record":{"id":"27847835d0213397","repo":"dotnet/reactive","slug":"value-cannot-be-null-parameter-disposable-278478","errorCode":null,"errorMessage":"Value cannot be null. (Parameter 'disposable')","messagePattern":"Value cannot be null\\. \\(Parameter 'disposable'\\)","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"AsyncRx.NET/System.Reactive.Async/Disposables/RefCountAsyncDisposable.cs","lineNumber":19,"sourceCode":"﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT License.\n// See the LICENSE file in the project root for more information. \n\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace System.Reactive.Disposables\n{\n    public sealed class RefCountAsyncDisposable : IAsyncDisposable\n    {\n        private readonly AsyncGate _gate = new();\n        private IAsyncDisposable _disposable;\n        private bool _primaryDisposed;\n        private int _count;\n\n        public RefCountAsyncDisposable(IAsyncDisposable disposable)\n        {\n            _disposable = disposable ?? throw new ArgumentNullException(nameof(disposable));\n            _primaryDisposed = false;\n            _count = 0;\n        }\n\n        public async ValueTask<IAsyncDisposable> GetDisposableAsync()\n        {\n            using (await _gate.LockAsync().ConfigureAwait(false))\n            {\n                if (_disposable == null)\n                {\n                    return AsyncDisposable.Nop;\n                }\n                else\n                {\n                    _count++;\n                    return new Inner(this);\n                }\n            }","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/AsyncRx.NET/System.Reactive.Async/Disposables/RefCountAsyncDisposable.cs#L1-L37","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nvar refCounted = new RefCountAsyncDisposable(_underlying); // _underlying is null\n// after\nif (_underlying == null)\n    throw new InvalidOperationException(\"Underlying disposable was not initialized.\");\nvar refCounted = new RefCountAsyncDisposable(_underlying);","handlingStrategy":"validation","validationCode":"if (underlying is null)\n    throw new InvalidOperationException(\"Underlying disposable must be created before ref-counting it.\");\nvar refCounted = new RefCountAsyncDisposable(underlying);","typeGuard":"bool HasDisposable([NotNullWhen(true)] IAsyncDisposable? d) => d is not null;","tryCatchPattern":"try\n{\n    var refCounted = new RefCountAsyncDisposable(underlying);\n}\ncatch (ArgumentNullException ex) when (ex.ParamName == \"disposable\")\n{\n    // underlying resource was never created; handle initialization failure here\n}","preventionTips":["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"],"tags":["csharp","null-reference","constructor","argument-validation"],"backgroundTag":"null-argument","analyzedSha":"94b5d5ab912789f5abe9a72138a25bbd716fe59c","analyzedAt":"2026-09-15T02:26:24.759Z","contentChangedAt":"2026-09-15T02:26:24.759Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}