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

  1. Move the set operation BEFORE the last Select call so both operands are still server-evaluated.
  2. Insert AsEnumerable() before the set operation to perform it client-side.
  3. 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

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


AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06). Data as JSON: /api/errors/1d6c332af472d48a. Report an issue: GitHub.