dotnet/efcore · error · InvalidOperationException
The LINQ expression ' ' could not be translated. Additional…
Error message
The LINQ expression '{expression}' could not be translated. Additional information: {details} Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information. What it means
The InMemory query translation preprocessor overrides Process and inspects the top-level expression tree after base preprocessing. If the result is a MethodCallExpression whose generic method definition is Queryable.GroupByWithKeySelector or Queryable.GroupByWithKeyElementSelector (i.e. a GroupBy that has NOT been composed into a further aggregation or projection), it throws TranslationFailedWithDetails with the detail message NonComposedGroupByNotSupported. The InMemory provider only supports GroupBy that is immediately followed by a server-translatable aggregate; a standalone GroupBy yielding IGrouping sequences is not supported.
Solutions
- Compose the GroupBy into an aggregate immediately: .GroupBy(...).Select(g => new { Key = g.Key, Count = g.Count() }).
- Insert AsEnumerable() before GroupBy to perform grouping entirely on the client side.
- If you need the raw groups, materialize with ToList() first then use LINQ-to-Objects GroupBy.
Example fix
// before — non-composed GroupBy producing IGrouping
var groups = ctx.Blogs.GroupBy(b => b.Author);
foreach (var g in groups) { /* iterate groups */ }
// after — compose into aggregate projection
var groups = ctx.Blogs
.GroupBy(b => b.Author)
.Select(g => new { Author = g.Key, Count = g.Count() });
// or — client-side grouping
var groups = ctx.Blogs.AsEnumerable().GroupBy(b => b.Author); Defensive patterns
Strategy: validation
Validate before calling
// Validate: ensure every GroupBy is immediately followed by a server-translatable
// aggregate or projection. If raw IGrouping sequences are needed, use AsEnumerable.
// Check: is the GroupBy result composed into Select(g => ...) with aggregates?
// Safe pattern:
var result = ctx.Blogs
.GroupBy(b => b.Author)
.Select(g => new { Author = g.Key, Count = g.Count() }); Try / catch
try
{
return query.ToList();
}
catch (InvalidOperationException ex) when (ex.Message.Contains("GroupBy"))
{
// Switch to client-side grouping
return query.AsEnumerable().GroupBy(keySelector).ToList();
} Prevention
- Always compose GroupBy into an aggregate (Count, Sum, Select of aggregate).
- If raw IGrouping sequences are needed, materialize with AsEnumerable() first.
- Avoid iterating GroupBy results directly from an IQueryable.
- Test GroupBy queries against the InMemory provider in integration tests.
When it happens
Trigger: Writing a query like ctx.Blogs.GroupBy(b => b.Author) or ctx.Blogs.GroupBy(b => b.Author, b => b.Title) where the GroupBy result (IGrouping) is consumed directly without a following aggregate (Sum, Count, Select of aggregate). The throw happens at preprocessing time before the query reaches the translator.
Common situations: Porting queries from EF Core SQL providers (which support GroupBy yielding groups in some versions) to InMemory tests, or writing grouping logic that assumes the provider can stream IGrouping sequences. Developers who iterate over Group By results with nested loops hit this.
Related errors
- The LINQ expression ' ' could not be translated. Either…
- Unable to translate set operation after client projection…
- 'DefaultIfEmpty' cannot be applied after a client-evaluated…
- Using 'Distinct' operation on a projection containing a…
- A synchronous store management operation was performed and…
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/ef08ec546c1b0172.
Report an issue: GitHub.
Appendix: source
Thrown at src/EFCore.InMemory/Query/Internal/InMemoryQueryTranslationPreprocessor.cs:42
QueryCompilationContext queryCompilationContext)
: base(dependencies, queryCompilationContext)
{
}
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public override Expression Process(Expression query)
{
var result = base.Process(query);
return result is MethodCallExpression { Method.IsGenericMethod: true } methodCallExpression
&& (methodCallExpression.Method.GetGenericMethodDefinition() == QueryableMethods.GroupByWithKeySelector
|| methodCallExpression.Method.GetGenericMethodDefinition() == QueryableMethods.GroupByWithKeyElementSelector)
? throw new InvalidOperationException(
CoreStrings.TranslationFailedWithDetails(methodCallExpression.Print(), InMemoryStrings.NonComposedGroupByNotSupported))
: result;
}
/// <inheritdoc />
protected override bool IsEfConstantSupported
=> true;
}
View on GitHub (pinned to 3a2006ef56)