dotnet/reactive · error · ArgumentNullException

Value cannot be null. (Parameter 'dispose')

Error message

Value cannot be null. (Parameter 'dispose')

What it means

Disposable.Create(Action dispose) throws ArgumentNullException when the dispose action is null. Create builds an AnonymousDisposable that invokes the given action on disposal; a null action would make disposal a no-op silently or crash later, so the factory validates eagerly. The contract is documented in the method's XML docs.

Solutions

  1. Provide a real action; use Disposable.Empty if no cleanup is needed.
  2. Null-check the delegate before calling Create and fall back to Disposable.Empty.
  3. Ensure the callback field is initialized at declaration (e.g. = () => {}) rather than left null.

Example fix

// before
var d = Disposable.Create(_cleanup); // _cleanup may be null
// after
var d = _cleanup != null ? Disposable.Create(_cleanup) : Disposable.Empty;
Defensive patterns

Strategy: validation

Validate before calling

if (cleanup == null) return Disposable.Empty;
var d = Disposable.Create(cleanup);

Type guard

IDisposable TryCreate(Action cleanup) => cleanup == null ? Disposable.Empty : Disposable.Create(cleanup);

Try / catch

try { var d = Disposable.Create(dispose); } catch (ArgumentNullException ex) when (ex.ParamName == "dispose") { d = Disposable.Empty; }

Prevention

When it happens

Trigger: Disposable.Create(null), often when the action is built from a delegate field/parameter that is null (unassigned callback, optional hook), or from a ternary/LINQ selection that produced null.

Common situations: Registering cleanup callbacks where the cleanup delegate is conditionally assigned; passing a method group resolved via reflection or a dictionary of handlers that missed the key.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Disposables/Disposable.cs:52

            }
        }

        /// <summary>
        /// Gets the disposable that does nothing when disposed.
        /// </summary>
        public static IDisposable Empty => EmptyDisposable.Instance;

        /// <summary>
        /// Creates a disposable object that invokes the specified action when disposed.
        /// </summary>
        /// <param name="dispose">Action to run during the first call to <see cref="IDisposable.Dispose"/>. The action is guaranteed to be run at most once.</param>
        /// <returns>The disposable object that runs the given action upon disposal.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="dispose"/> is <c>null</c>.</exception>
        public static IDisposable Create(Action dispose)
        {
            if (dispose == null)
            {
                throw new ArgumentNullException(nameof(dispose));
            }

            return new AnonymousDisposable(dispose);
        }

        /// <summary>
        /// Creates a disposable object that invokes the specified action when disposed.
        /// </summary>
        /// <param name="state">The state to be passed to the action.</param>
        /// <param name="dispose">Action to run during the first call to <see cref="IDisposable.Dispose"/>. The action is guaranteed to be run at most once.</param>
        /// <returns>The disposable object that runs the given action upon disposal.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="dispose"/> is <c>null</c>.</exception>
        public static IDisposable Create<TState>(TState state, Action<TState> dispose)
        {
            if (dispose == null)
            {
                throw new ArgumentNullException(nameof(dispose));
            }

View on GitHub (pinned to 94b5d5ab91)