dotnet/reactive · error · InvalidOperationException

MORE_THAN_ONE_MATCHING_ELEMENT

Error message

MORE_THAN_ONE_MATCHING_ELEMENT

What it means

The predicate-based overload of SingleOrDefaultAsync throws InvalidOperationException(MORE_THAN_ONE_MATCHING_ELEMENT) in OnNext when a second element passes the predicate after one already matched. The operator asserts that at most one element of the source satisfies the filter; any additional match is a contract violation surfaced via OnError.

Solutions

  1. Tighten the predicate so it matches exactly one element (filter on a true unique key).
  2. Use .Where(predicate).Take(1) plus FirstOrDefaultAsync when multiple matches are legal and any one suffices.
  3. Deduplicate the source first (Distinct/DistinctBy semantics via GroupBy+SelectMany) before applying the operator.
  4. Catch the InvalidOperationException and decide how to handle genuinely duplicated matches.

Example fix

// before
var user = await users.SingleOrDefaultAsync(u => u.Email == email); // throws on duplicate emails

// after
var user = await users.Where(u => u.Email == email).Take(1).LastOrDefaultAsync();
// or enforce uniqueness upstream on the email column
Defensive patterns

Strategy: validation

Validate before calling

// Verify predicate uniqueness against the data before relying on the operator:
int matches = await source.Where(predicate).Count();
if (matches > 1) { /* resolve duplicates (tighten key, deduplicate) first */ }

Type guard

static bool MatchesAtMostOne<T>(IList<T> items, Func<T, bool> predicate) => items.Count(predicate) <= 1;

Try / catch

source.SingleOrDefaultAsync(predicate).Subscribe(
    value => { /* use value or default */ },
    ex => { if (ex is InvalidOperationException) { /* multiple matches: log and choose first */ } else throw ex; });

Prevention

When it happens

Trigger: Calling Observable.SingleOrDefaultAsync(source, predicate) where two or more source elements satisfy the predicate. Raised in the OnNext path at SingleOrDefaultAsync.cs:106 after evaluating the predicate to true while _seenValue is already true.

Common situations: Filtering by a key assumed unique (e.g. x => x.Id == targetId) against data containing duplicates after a merge/import; predicates that are looser than intended (matching multiple rows in a DB-backed stream); schema changes that break a uniqueness assumption.

Related errors


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

Appendix: source

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

                    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()
                {
                    ForwardOnNext(_value);
                    ForwardOnCompleted();
                }

View on GitHub (pinned to 94b5d5ab91)