dotnet/reactive · error · InvalidOperationException

Strings_Linq.NO_ELEMENTS

Error message

Strings_Linq.NO_ELEMENTS

What it means

The Rx Max operator tracks whether the source sequence produced any element. When the observer's OnCompleted fires and no value was ever seen, the operator cannot produce a maximum, so it throws System.InvalidOperationException with the message Strings_Linq.NO_ELEMENTS ("Sequence contains no elements"). This mirrors the synchronous LINQ-to-Objects behavior of Enumerable.Max on an empty sequence: an aggregate over zero items is undefined rather than null.

Solutions

  1. Ensure the source can emit at least one value, or validate emptiness before aggregating.
  2. Use MaxOrDefault-style behavior by prepending a default: source.DefaultIfEmpty(0).Max().
  3. Use Observable.Empty detection first, e.g. Any(): await source.Any() before calling Max, or branch on it.
  4. For nullable-friendly semantics, aggregate with Scan + LastOrDefaultAsync or use System.Linq.AsyncEnumerable MaxAsync which throws only per its own contract.
  5. If the empty case is expected, catch InvalidOperationException around the subscription and supply a fallback value.

Example fix

// before
var max = await temperatures.Max(); // throws if temperatures is empty

// after
var max = await temperatures
    .DefaultIfEmpty(double.NaN)
    .Max(); // NaN sentinel instead of InvalidOperationException
Defensive patterns

Strategy: validation

Validate before calling

bool hasAny = await source.Any();
if (!hasAny) return defaultValue; // avoids InvalidOperationException from Max
var max = await source.Max();

Type guard

static async Task<bool> IsEmptyAsync<T>(this IObservable<T> source) =>
    !await source.Any();

Try / catch

try
{
    var max = await source.Max();
    return max;
}
catch (InvalidOperationException ex) when (ex.Message == Strings_Linq.NO_ELEMENTS)
{
    return defaultValue;
}

Prevention

When it happens

Trigger: Subscribing to Observable.Max over a source that completes without emitting any element — e.g. Observable.Empty<int>().Max(), a Where/filter that excludes every item, or an observable that completes immediately — and the anonymous observer in Max.cs (line ~78) reaches OnCompleted with _hasValue == false.

Common situations: Filtering a stream with a predicate that matches nothing (e.g. temperatures.Where(t => t > 100).Max()); querying a data feed that returns an empty batch; time-windowed aggregations where no events arrived during the window; race where the source completes before the first value due to cancellation or a hot sequence already finished.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


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

Appendix: source

Thrown at Rx.NET/Source/src/System.Reactive/Linq/Observable/Max.cs:78

                    if (comparison > 0)
                    {
                        _lastValue = value;
                    }
                }
                else
                {
                    _hasValue = true;
                    _lastValue = value;
                }
            }

            public override void OnCompleted()
            {
                if (!_hasValue)
                {
                    try
                    {
                        throw new InvalidOperationException(Strings_Linq.NO_ELEMENTS);
                    }
                    catch (Exception e)
                    {
                        ForwardOnError(e);
                    }
                }
                else
                {
                    ForwardOnNext(_lastValue!);
                    ForwardOnCompleted();
                }
            }
        }

        private sealed class Null : _
        {
            private TSource? _lastValue;

View on GitHub (pinned to 94b5d5ab91)