dotnet/reactive · error · ArgumentNullException

stateMachine

Error message

stateMachine

What it means

AsyncTaskMethodBuilder-style Start<TStateMachine> in the custom TaskObservableMethodBuilder throws ArgumentNullException when the state machine box is null. The compiler-generated async state machine is passed by ref to Start, which calls MoveNext to begin execution; a null machine cannot run. This builder is used by async methods returning IObservable-based tasks, and null here almost always means the async method builder infrastructure was invoked incorrectly.

Solutions

  1. Do not call Start manually — let the C# compiler construct and start the state machine for async methods using this builder.
  2. If you must call it, construct the TStateMachine struct (never pass null/default-of-reference) before Start.
  3. Check that IL-rewriting tooling (profiler, weaver, mocking library) supports this async method builder and is up to date.
  4. Rebuild/reinstall System.Reactive so compiler-generated builder bindings match the library version.

Example fix

// before
TaskObservableMethodBuilder<int> b = default;
MyStateMachine machine = null; // invalid
b.Start(ref machine);
// after
var b = TaskObservableMethodBuilder<int>.Create();
var machine = new MyStateMachine { Builder = b };
b.Start(ref machine); // compiler does this automatically for async methods
Defensive patterns

Strategy: try-catch

Validate before calling

if (stateMachine == null) throw new ArgumentNullException(nameof(stateMachine)); // guard before calling builder.Start

Type guard

bool CanStart<TStateMachine>(TStateMachine m) where TStateMachine : class, IAsyncStateMachine => m != null;

Try / catch

try { builder.Start(ref stateMachine); }
catch (ArgumentNullException ex) when (ex.ParamName == "stateMachine") { /* state machine was not constructed; inspect async tooling/rewriters */ throw; }

Prevention

When it happens

Trigger: Calling builder.Start<TStateMachine>(ref machine) manually with an uninitialized (null) state machine, or custom/rewritten async tooling (e.g. post-processing IL rewriters, custom awaiter libraries) that fails to construct the state machine struct before calling Start.

Common situations: Custom async-method-builder experiments targeting Rx observables; IL-weaving or AOP frameworks (profilers, mocking tools) that rewrite async state machines; debugging stepping into builder internals after a broken build.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Runtime/CompilerServices/TaskObservableMethodBuilder.cs:54

#pragma warning disable CA1000 // (Do not declare static members on generic types.) Async method builders are required to define a static Create method, and are require to be generic when the async type produces a result.
        public static TaskObservableMethodBuilder<T> Create() => default;
#pragma warning restore CA1000 // Do not declare static members on generic types

        /// <summary>
        /// Begins running the builder with the associated state machine.
        /// </summary>
        /// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
        /// <param name="stateMachine">The state machine instance, passed by reference.</param>
        /// <exception cref="ArgumentNullException"><paramref name="stateMachine"/> is <c>null</c>.</exception>
#pragma warning disable CA1045 // (Avoid ref.) Required because this is an async method builder
#pragma warning disable IDE0251 // (Make readonly.) Not part of the standard method builder pattern.
        public void Start<TStateMachine>(ref TStateMachine stateMachine)
#pragma warning restore CA1045, IDE0251
            where TStateMachine : IAsyncStateMachine
        {
            if (stateMachine == null)
            {
                throw new ArgumentNullException(nameof(stateMachine));
            }

            stateMachine.MoveNext();
        }

        /// <summary>
        /// Associates the builder with the specified state machine.
        /// </summary>
        /// <param name="stateMachine">The state machine instance to associate with the builder.</param>
        /// <exception cref="ArgumentNullException"><paramref name="stateMachine"/> is <c>null</c>.</exception>
        /// <exception cref="InvalidOperationException">The state machine was previously set.</exception>
        public void SetStateMachine(IAsyncStateMachine stateMachine)
        {
            if (_stateMachine != null)
            {
                throw new InvalidOperationException();
            }

View on GitHub (pinned to 94b5d5ab91)