Start Debugging

Fix: System.InvalidOperationException: Sequence contains no elements

This exception means you called .First() or .Single() on an empty sequence. Use FirstOrDefault/SingleOrDefault and null-check, or guard the query, or fix why the source is empty.

System.InvalidOperationException: Sequence contains no elements means you called .First(), .Single(), .Last(), or one of their aggregate cousins (.Average(), .Max(), .Min()) on a sequence that turned out to be empty. The operator promised to return an element and there was none, so it threw. The fix is to decide what “empty” should mean for that call: if empty is a normal outcome, switch to .FirstOrDefault() / .SingleOrDefault() and handle the null (or default) you get back; if empty is a bug, fix the query or the data so the sequence is never empty at that point. This is verified against .NET 11, C# 14, and EF Core 11.0.0, but the message and behavior have been stable since LINQ shipped in .NET Framework 3.5, so the guidance applies to every version.

The error in context

The full exception, thrown from inside System.Linq, looks like this:

System.InvalidOperationException: Sequence contains no elements
   at System.Linq.ThrowHelper.ThrowNoElementsException()
   at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
   at MyApp.OrderService.GetLatest() in /src/OrderService.cs:line 42

The giveaway is the top frame: System.Linq.ThrowHelper.ThrowNoElementsException. If you see that in the stack, an element-returning LINQ operator ran against an empty source. The exact wording matters for search, because LINQ throws four closely related messages from the same class and they mean different things:

This post is about the first one. The others are covered in the variants section, because landing on the wrong one wastes your time.

Why this happens

.First() and .Single() are contract operators: their return type is a non-nullable TSource, so they have no way to signal “nothing here” except by throwing. When the source is empty, there is no element to hand back, and returning default(TSource) would be a lie for a reference type (you would get null where the signature promised a value). So the runtime throws InvalidOperationException instead. That is a deliberate design choice, not a bug: the *OrDefault variants exist precisely for the case where empty is acceptable.

The confusing part is that the sequence is often empty for reasons that are invisible at the call site. A Where filter upstream removed every row. A database table has no matching record yet. A collection was cleared, or was never populated because an earlier await failed silently. The exception fires on the .First() line, but the real cause is three lines (or three method calls) earlier. That is why “just wrap it in try/catch” is rarely the right instinct: you want to know why the sequence is empty, not just swallow the symptom.

Minimal repro

The smallest code that throws it:

// .NET 11, C# 14
var numbers = new List<int>();     // empty
int first = numbers.First();       // System.InvalidOperationException: Sequence contains no elements

The same thing happens when a filter eliminates everything, which is the far more common real-world shape:

// .NET 11, C# 14
var orders = new List<Order>
{
    new(Id: 1, Status: "shipped"),
    new(Id: 2, Status: "shipped"),
};

// No pending orders exist, so the filtered sequence is empty.
Order next = orders.First(o => o.Status == "pending");
// System.InvalidOperationException: Sequence contains no matching element

Note the second message is the no matching element variant, because a predicate was supplied. Both come from the same family of bugs: you assumed at least one element would be there, and it was not.

Fix, in detail

Work through these in order. The first two cover almost every real occurrence.

1. Use FirstOrDefault / SingleOrDefault and handle the empty case

If an empty sequence is a legitimate outcome (no rows yet, an optional lookup, a search that can miss), switch to the *OrDefault overload and check what you get back:

// .NET 11, C# 14
Order? next = orders.FirstOrDefault(o => o.Status == "pending");
if (next is null)
{
    // No pending order. Handle it: return early, use a fallback, log, whatever fits.
    return;
}
Process(next);

FirstOrDefault returns default(TSource) when the sequence is empty: null for a reference type, 0 for int, default for a struct. On a nullable-annotated codebase (<Nullable>enable</Nullable>, the default in new .NET 11 templates), the compiler types the result as Order? and will nag you until you null-check it, which is exactly the safety you want. Do not skip the check: replacing First with FirstOrDefault and then immediately dereferencing the result just trades InvalidOperationException for a NullReferenceException one line later. If the nullable warnings feel noisy, that is the compiler pointing at the real work, and it ties directly into CS8618 and non-nullable properties.

Since .NET 6 there is also an overload that lets you supply your own default, which is cleaner than a separate null-check when you have a sensible fallback:

// .NET 11, C# 14 -- FirstOrDefault(predicate, defaultValue) added in .NET 6
Order next = orders.FirstOrDefault(o => o.Status == "pending", Order.None);

2. Guard the sequence before you call First

When you genuinely need the first element but only if one exists, check emptiness first. For an in-memory collection, Count or Any() is enough:

// .NET 11, C# 14
if (orders.Count > 0)
{
    Order first = orders.First();   // safe: we know it is non-empty
    Process(first);
}

Prefer Count (or Count > 0) for anything that implements ICollection<T>, such as List<T> or an array, because it is O(1). Use .Any() for a lazily-evaluated IEnumerable<T> where you cannot cheaply get a count. Do not write if (orders.Count() > 0) on a lazy sequence: Count() enumerates the entire thing, whereas Any() stops after the first element.

3. Fix why the sequence is empty

Sometimes empty is the bug, not a valid state. If orders.First(o => o.Status == "pending") should always find a row and does not, the real fix is upstream: a filter that is too strict, a case-sensitivity mismatch ("Pending" vs "pending"), a join that dropped rows, or data that was never inserted. Reach for a *OrDefault here only after you have confirmed the sequence is allowed to be empty. Swallowing a “this should never be empty” case with FirstOrDefault hides a genuine data or logic error and moves the crash somewhere harder to diagnose.

4. For aggregates, use a nullable overload or DefaultIfEmpty

.Average(), .Max(), .Min(), and .Sum() share the same trap. .Average() and the value-type .Max()/.Min() throw Sequence contains no elements on an empty source (.Sum() returns 0, which is its own surprise). Two clean fixes:

// .NET 11, C# 14
var prices = new List<int>();

// Option A: project to a nullable so the aggregate returns null instead of throwing.
double? avg = prices.Average(p => (int?)p);   // null when empty, no exception

// Option B: supply a fallback element before aggregating.
int max = prices.DefaultIfEmpty(0).Max();     // 0 when empty

DefaultIfEmpty is the general-purpose escape hatch: it yields a single default element when the source is empty, so any downstream operator, including .First(), sees at least one item.

Gotchas and variants

A few situations produce this exception, or a close relative, for reasons the message does not spell out:

The mental model to keep: .First() and .Single() are assertions that an element exists. Sequence contains no elements is that assertion failing. Decide whether the empty case is legal. If it is, express that with FirstOrDefault/SingleOrDefault and handle the default you get back. If it is not, fix the query or the data upstream so the sequence is never empty at that point, rather than papering over it at the call site.

Sources

Comments

Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.

< Back