dotnet/efcore · error · InvalidOperationException
Empty collections are not supported as inline query roots.
Error message
Empty collections are not supported as inline query roots.
What it means
GenerateValues refuses to render a VALUES inline query root that contains zero rows. EF translates certain in-memory collections used as query roots into a VALUES construct; an empty collection has no columns/types to project, so SQL generation is impossible. The check is hit at SQL-generation time, meaning the query already passed translation with an empty row set.
Source
Thrown at src/EFCore.Relational/Query/QuerySqlGenerator.cs:1620
_relationalCommandBuilder
.Append(")")
.Append(AliasSeparator)
.Append(_sqlGenerationHelper.DelimitIdentifier(valuesExpression.Alias));
return valuesExpression;
}
/// <summary>
/// Generates SQL for a VALUES expression.
/// </summary>
/// <param name="valuesExpression">The <see cref="ValuesExpression" /> for which to generate SQL.</param>
protected virtual void GenerateValues(ValuesExpression valuesExpression)
{
var rowValues = valuesExpression switch
{
{ RowValues.Count: 0 }
=> throw new InvalidOperationException(RelationalStrings.EmptyCollectionNotSupportedAsInlineQueryRoot),
{ ValuesParameter: not null }
=> throw new UnreachableException(
"ValuesExpression.ValuesParameter has to be expanded to constants before SQL generation (i.e. in SqlNullabilityProcessor)"),
{ RowValues: not null } => valuesExpression.RowValues,
_ => throw new UnreachableException()
};
// Some databases support providing the names of columns projected out of VALUES, e.g.
// SQL Server/PG: (VALUES (1, 3), (2, 4)) AS x(a, b). Others unfortunately don't; so by default, we extract out the first row,
// and generate a SELECT for it with the names, and a UNION ALL over the rest of the values.
_relationalCommandBuilder.Append("SELECT ");
Check.DebugAssert(rowValues.Count > 0);
var firstRowValues = rowValues[0].Values;
for (var i = 0; i < firstRowValues.Count; i++)View on GitHub (pinned to 3a2006ef56)
Solutions
- Short-circuit before the query when the collection is empty (return an empty result or skip the predicate/join).
- For Contains filters, build the predicate conditionally so EF never inlines an empty VALUES: if (ids.Count > 0) query = query.Where(e => ids.Contains(e.Id));
- Avoid using empty in-memory sequences as query roots; materialize the server side first, then join in memory.
Example fix
// before
var q = from e in db.Entities
from id in ids.AsQueryable() // ids may be empty -> 585
select new { e, id };
// after
if (ids.Count == 0) return Array.Empty<Result>();
var q = from e in db.Entities
from id in ids.AsQueryable()
select new { e, id }; Defensive patterns
Strategy: validation
Validate before calling
// Never hand EF an empty inline collection as a query root / Contains source.
if (ids is null || ids.Count == 0)
return Array.Empty<Result>();
var q = db.Entities.Where(e => ids.Contains(e.Id));
// For an in-memory root join:
if (memoryList.Count == 0) return Enumerable.Empty<Result>(); Prevention
- Guard dynamic filter lists for emptiness before composing Contains/join.
- Build Contains predicates conditionally so EF never sees an empty VALUES root.
- Materialize server data first, then join in memory when the in-memory side may be empty.
When it happens
Trigger: Using an empty in-memory collection as a query root in a composed query that EF translates server-side, e.g. from e in db.Entities from id in emptyArray.AsQueryable() select e, or Contains over a parameterized empty list that EF chose to inline as VALUES instead of a parameter. Also seen with open-ended composition where a sub-source resolves empty at execution.
Common situations: Dynamic filters where a list can be empty (e.g. var ids = FilterIds(); ... where ids.Contains(e.Id)); joining against an in-memory list that happens to be empty for a given request; unit/integration tests passing empty collections.
Related errors
- The LINQ expression '{expression}' could not be translated.
- Unable to translate set operation after client projection ha
- 'DefaultIfEmpty' cannot be applied after a client-evaluated
- Using 'Distinct' operation on a projection containing a subq
- The LINQ expression '{expression}' could not be translated.
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/347bfdce39d2e7e7.
Report an issue: GitHub.