dotnet/reactive · error · InvalidOperationException

MORE_THAN_ONE_MATCHING_ELEMENT

Error message

MORE_THAN_ONE_MATCHING_ELEMENT

What it means

The predicate-based SingleAsync overload throws InvalidOperationException(Strings_Linq.MORE_THAN_ONE_MATCHING_ELEMENT) when a second element satisfying the predicate arrives after one was already matched, forwarding it via OnError. It enforces 'exactly one matching element' like LINQ's Single(predicate).

Solutions

  1. Tighten the predicate so exactly one element matches, or deduplicate upstream with Distinct/DistinctUntilChanged.
  2. Use FirstAsync(predicate) when only the first match is needed, or SingleOrDefaultAsync if zero-or-one is acceptable.
  3. Fix the underlying data/source so the uniqueness invariant actually holds.

Example fix

// before
var active = await sessions.SingleAsync(s => s.IsActive);
// after
var active = await sessions.Where(s => s.IsActive).Take(1).FirstAsync();
Defensive patterns

Strategy: fallback

Try / catch

try { var v = await source.SingleAsync(x => x.IsActive); }
catch (InvalidOperationException) { var v = await source.Where(x => x.IsActive).FirstAsync(); }

Prevention

When it happens

Trigger: source.SingleAsync(x => predicate(x)) on a stream where two distinct OnNext values satisfy the predicate before completion.

Common situations: Selecting 'the' active record (e.g. current session, default profile) where data integrity allows several active rows; race conditions creating duplicates; a predicate written too loosely (e.g. status == Active matching stale rows).

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable/SingleAsync.cs:120

                    var b = false;

                    try
                    {
                        b = _predicate(value);
                    }
                    catch (Exception ex)
                    {
                        ForwardOnError(ex);
                        return;
                    }

                    if (b)
                    {
                        if (_seenValue)
                        {
                            try
                            {
                                throw new InvalidOperationException(Strings_Linq.MORE_THAN_ONE_MATCHING_ELEMENT);
                            }
                            catch (Exception e)
                            {
                                ForwardOnError(e);
                            }
                            return;
                        }

                        _value = value;
                        _seenValue = true;
                    }
                }

                public override void OnCompleted()
                {
                    if (!_seenValue)
                    {
                        try

View on GitHub (pinned to 94b5d5ab91)