The analyzer understands LINQ query operators on both IEnumerable<T> and IAsyncEnumerable<T> (via System.Linq.Async). Support for IQueryable<T> is enabled by default; disable it with disableLinqQueryableSupport if your provider cannot translate the expressions.
Async operator names such as FirstAsync or FirstAwaitWithCancellation are normalized to their synchronous counterparts so the same exception knowledge applies.
⚠️ Translation ofIQueryable<T>expressions depends on the LINQ provider. Disable support withdisableLinqQueryableSupportif your provider cannot evaluate the expressions similarly to LINQ-to-Objects.
LINQ is built on deferred execution. The operations (with their predicates/selectors) get chained, resulting in a chain of query objects that implement IEnumerable<T>. The query is executed only when a terminator operator runs (e.g., First, Any, ToArray) or when you iterate it with foreach. That’s when results are materialized—and where exceptions can occur.
Here’s an example that uses a terminator with a predicate. The predicate can throw, and the diagnostic is reported on the terminator call:
IEnumerable<string> values = [ "10", "x", "20" ];
var allEven = values
.Where(v => v.Length > 0)
.All(v => int.Parse(v) % 2 is 0);
// Reported on All(...):
// THROW001: Unhandled exception type 'FormatException'
// THROW001: Unhandled exception type 'OverflowException'Exceptions are inferred and implicit on LINQ methods. Any explicit
[Throws]on LINQ lambdas is reported as redundant. This behavior can be disabled.
This differs from First()/Single() cases by not adding its own “empty/duplicate” errors—All only reflects exceptions from the predicate.
Async pipelines work the same way:
IAsyncEnumerable<int> items = default!;
var query = items.Where([Throws(typeof(FormatException), typeof(OverflowException))] (x) => x == int.Parse("10"));
var r = await query.FirstAsync();
// THROW001: FormatException, OverflowException, InvalidOperationExceptionA different shape: a mid-stream predicate on a deferred operator, evaluated during enumeration. Diagnostics are issued on the query expression being iterated.
IEnumerable<string> dates = [ "2001-01-01", "oops", "2005-12-31" ];
var recent = dates
.TakeWhile([Throws(s => DateTime.Parse(s).Year >= 2000);
// Reported on "recent":
// THROW001: Unhandled exception type 'FormatException'
foreach (var d in recent)
{
// Enumeration triggers evaluation of TakeWhile's predicate
}This shows exceptions surfacing during enumeration rather than on a terminal method call.
There is no way to indicate that a parameter, field, or property of type IEnumerable<T> might be throwing exceptions.
The recommended approach is to handle exceptions from enumerables locally and expose a materialized collection type instead.