dotnet/reactive · error · InvalidOperationException

MORE_THAN_ONE_ELEMENT

Error message

MORE_THAN_ONE_ELEMENT

What it means

SingleOrDefaultAsync throws InvalidOperationException(MORE_THAN_ONE_ELEMENT) from OnNext when a second element arrives after one was already observed. 'OrDefault' only relaxes the empty case, not the uniqueness requirement: the sequence must contain at most one element. The error is forwarded via OnError as soon as the duplicate value is seen, cancelling further processing.

Solutions

  1. Use Take(1) (or FirstOrDefaultAsync) if only the first element is needed and duplicates are expected.
  2. Use .DistinctUntilChanged() before SingleOrDefaultAsync if duplicate values should be collapsed.
  3. If the source is truly required to be unique, fix the producer so it never emits more than one value.
  4. Catch InvalidOperationException from the subscription and fall back to the default or last-known value.

Example fix

// before
var value = await updates.SingleOrDefaultAsync(); // throws if 2+ updates arrive

// after
var value = await updates.Take(1).LastOrDefaultAsync(); // first update, no throw
// or if uniqueness is contractual:
var value = await updates.DistinctUntilChanged().SingleOrDefaultAsync();
Defensive patterns

Strategy: validation

Validate before calling

// Enforce single-emission at the producer, or buffer and check count:
var buffered = await source.ToList();
if (buffered.Count > 1) { /* handle duplicates before calling SingleOrDefaultAsync */ }

Type guard

static bool HasAtMostOne<T>(IList<T> buffered) => buffered.Count <= 1;

Try / catch

source.SingleOrDefaultAsync().Subscribe(
    value => { /* use value or default */ },
    ex => { if (ex is InvalidOperationException) { /* duplicate element path: fall back to First */ } else throw ex; });

Prevention

When it happens

Trigger: Calling Observable.SingleOrDefaultAsync(source) on a hot or cold observable that emits two or more OnNext values. Raised in the observer's OnNext override at SingleOrDefaultAsync.cs:38 when _seenValue is already true.

Common situations: Assuming SingleOrDefault behaves like ElementAt(0)/First with a fallback; streams that legitimately emit multiple updates (e.g. repeated config pushes, retries emitting duplicates); replacing First with SingleOrDefault without checking cardinality guarantees.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable/SingleOrDefaultAsync.cs:38

            protected override void Run(_ sink) => sink.Run(_source);

            internal sealed class _ : Sink<TSource, TSource?>
            {
                private TSource? _value;
                private bool _seenValue;

                public _(IObserver<TSource?> observer)
                    : base(observer)
                {
                }

                public override void OnNext(TSource value)
                {
                    if (_seenValue)
                    {
                        try
                        {
                            throw new InvalidOperationException(Strings_Linq.MORE_THAN_ONE_ELEMENT);
                        }
                        catch (Exception e)
                        {
                            ForwardOnError(e);
                        }
                        return;
                    }

                    _value = value;
                    _seenValue = true;
                }

                public override void OnCompleted()
                {
                    ForwardOnNext(_value);
                    ForwardOnCompleted();
                }
            }

View on GitHub (pinned to 94b5d5ab91)