dotnet/efcore · error · InvalidOperationException
Unable to translate set operation after client projection ha
Error message
Unable to translate set operation after client projection has been applied. Consider moving the set operation before the last 'Select' call.
What it means
ApplySetOperation (Union/Concat/Intersect/Except) checks _clientProjections.Count and throws if a client-evaluated projection has already been applied (InMemoryQueryExpression.cs:444-446). The InMemory provider can only combine two queries in pure server-evaluation form; once the projection becomes client-side, set operations are not supported.
Source
Thrown at src/EFCore.InMemory/Query/Internal/InMemoryQueryExpression.cs:446
NewArrayInit(
typeof(object),
source1SelectorExpressions.Select(e => e.Type.IsValueType ? Convert(e, typeof(object)) : e))),
CurrentParameter));
source2.ServerQueryExpression = Call(
EnumerableMethods.Select.MakeGenericMethod(source2.ServerQueryExpression.Type.GetSequenceType(), typeof(ValueBuffer)),
source2.ServerQueryExpression,
Lambda(
New(
ValueBufferConstructor,
NewArrayInit(
typeof(object),
source2SelectorExpressions.Select(e => e.Type.IsValueType ? Convert(e, typeof(object)) : e))),
source2.CurrentParameter));
}
else
{
throw new InvalidOperationException(InMemoryStrings.SetOperationsNotAllowedAfterClientEvaluation);
}
ServerQueryExpression = Call(
setOperationMethodInfo.MakeGenericMethod(typeof(ValueBuffer)), ServerQueryExpression, source2.ServerQueryExpression);
}
/// <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 virtual void ApplyDefaultIfEmpty()
{
if (_clientProjections.Count != 0)
{
throw new InvalidOperationException(InMemoryStrings.DefaultIfEmptyAppliedAfterProjection);
}View on GitHub (pinned to dbf9771522)
Solutions
- Move the set operation BEFORE the last Select call so both operands are still server-evaluated.
- Insert AsEnumerable() before the set operation to perform it client-side.
- Remove client-evaluated expressions from the Select preceding the set operation.
Example fix
// before
var q = db.Users.Select(u => new { u.Id, Name = u.First + " " + u.Last })
.Union(db.Admins.Select(a => new { a.Id, Name = a.First + " " + a.Last }));
// after
var q = db.Users.Union(db.Admins)
.Select(x => new { x.Id, Name = x.First + " " + x.Last }); Defensive patterns
Strategy: try-catch
Try / catch
try
{
var r = q1.Select(proj).Concat(q2.Select(proj)).ToList();
}
catch (InvalidOperationException ex) when (ex.Message.Contains("set operation after client projection"))
{
var r = q1.AsEnumerable().Select(proj)
.Concat(q2.AsEnumerable().Select(proj)).ToList();
} Prevention
- Place Union/Concat/Intersect/Except BEFORE any Select that triggers client evaluation.
- When combining two sources, project after the set operation, not before.
- Use AsEnumerable() before the set operation to perform it client-side when needed.
When it happens
Trigger: Calling a set operation (Union/Concat/Intersect/Except) AFTER a Select that triggered client evaluation, e.g. db.Set<A>().Select(a => clientSideExpr).Concat(db.Set<B>().Select(...)).
Common situations: Combining two queries with Union/Concat where each side has a projection containing client-side computation, or projecting a DTO then unioning. Common when porting SQL UNION-style queries to LINQ.
Related errors
- The LINQ expression '{expression}' could not be translated.
- '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.
- This enumerator cannot be reset.
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/1d6c332af472d48a.
Report an issue: GitHub.