dotnet/reactive · error · InvalidOperationException

The observer has already terminated.

Error message

The observer has already terminated.

What it means

TryEnter is a serialization guard on the observer's status: it uses Interlocked.CompareExchange to ensure only one notification is processed at a time. This message fires when the status is Done, i.e. OnErrorAsync or OnCompletedAsync was already called and the observer is terminated — any further OnNextAsync/OnErrorAsync/OnCompletedAsync is illegal. Fix: stop issuing notifications after termination, or create a fresh observer.

Solutions

  1. Stop emitting from the source once OnCompleted/OnError has been signaled (e.g. gate emission with the subscription disposable).
  2. Track termination state in the producer before calling OnNextAsync.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at AsyncRx.NET/System.Reactive.Async/AsyncObserverBase.cs:78 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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

Appendix: source

Thrown at AsyncRx.NET/System.Reactive.Async/AsyncObserverBase.cs:78

            }
            finally
            {
                Interlocked.Exchange(ref _status, Idle);
            }
        }

        protected abstract ValueTask OnNextAsyncCore(T value);

        private void TryEnter()
        {
            var old = Interlocked.CompareExchange(ref _status, Busy, Idle);

            switch (old)
            {
                case Busy:
                    throw new InvalidOperationException("The observer is currently processing a notification.");
                case Done:
                    throw new InvalidOperationException("The observer has already terminated.");
            }
        }
    }
}

View on GitHub (pinned to 94b5d5ab91)