dotnet/efcore · error · InvalidOperationException

The LINQ expression '{expression}' could not be translated.

Error message

The LINQ expression '{expression}' could not be translated. 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

Thrown by RelationalProjectionBindingExpressionVisitor (line 131) when an index-based (client-side) projection encounters a ParameterExpression that cannot be translated to SQL. This is EF's generic 'LINQ expression could not be translated' failure: the query contains a construct that has no SQL equivalent, so EF refuses to evaluate it server-side and (without explicit client-evaluation opt-in) aborts. The message directs you to force client evaluation explicitly if that is intended.

Source

Thrown at src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs:131

            case null:
                return null;

            case not null when _indexBasedBinding:
            {
                switch (expression)
                {
                    case ConstantExpression:
                        return expression;

                    case QueryParameterExpression queryParameterExpression:
                        return Expression.Call(
                            GetParameterValueMethodInfo.MakeGenericMethod(queryParameterExpression.Type),
                            QueryCompilationContext.QueryContextParameter,
                            Expression.Constant(queryParameterExpression.Name));

                    case ParameterExpression parameterExpression:
                        throw new InvalidOperationException(CoreStrings.TranslationFailed(parameterExpression.Print()));

                    case ProjectionBindingExpression projectionBindingExpression:
                        return _selectExpression.GetProjection(projectionBindingExpression) switch
                        {
                            StructuralTypeProjectionExpression projection => AddClientProjection(projection, typeof(ValueBuffer)),
                            SqlExpression mappedSqlExpression => AddClientProjection(mappedSqlExpression, expression.Type.MakeNullable()),
                            // A single-result subquery (e.g. the group element of GroupBy(k).Select(g => g.First()))
                            // being composed over: lower it into the current select as a to-one join so the result
                            // has a bindable shape, instead of failing.
                            ShapedQueryExpression
                            {
                                ResultCardinality: ResultCardinality.Single or ResultCardinality.SingleOrDefault
                            } singleResultSubquery
                                => LowerSingleResultSubquery(projectionBindingExpression, singleResultSubquery),
                            _ => throw new InvalidOperationException(CoreStrings.TranslationFailed(projectionBindingExpression.Print()))
                        };

                    case MaterializeCollectionNavigationExpression materializeCollectionNavigationExpression:

View on GitHub (pinned to dbf9771522)

Solutions

  1. Rewrite the projection to use only translatable operations (mapped properties, supported LINQ operators).
  2. If client evaluation is intended, insert AsEnumerable()/ToListAsync() before the non-translatable part to switch to in-memory.
  3. Move arbitrary computations out of the IQueryable and apply them after materialization.
  4. Replace custom method calls with expression-tree-compatible equivalents or raw SQL (FromSqlRaw) where needed.
  5. Check the linked docs (go.microsoft.com/fwlink/?linkid=2101038) for supported translation patterns.

Example fix

// before - custom method + closure in projection cannot translate
var prefix = GetPrefix();
var q = context.Users.Select(u => FormatLabel(u.Name, prefix)).ToList();

// after - materialize first, then compute client-side
var users = context.Users.Select(u => new { u.Id, u.Name }).AsEnumerable()
    .Select(u => FormatLabel(u.Name, prefix)).ToList();
Defensive patterns

Strategy: validation

Validate before calling

// Keep non-translatable logic out of the IQueryable projection.
// Project only mapped properties server-side, then compute client-side.
var server = ctx.Users.Select(u => new { u.Id, u.Name }).AsEnumerable();
var result = server.Select(u => ClientOnly(u.Name)).ToList();

Type guard

// Heuristic: avoid closures/custom methods inside IQueryable Select.
static bool IsTranslatable(Expression e) => e is MemberExpression or BinaryExpression
    || e is MethodCallExpression m && (m.Method.DeclaringType == typeof(EF)
        || m.Method.DeclaringType == typeof(Math) || m.Method.DeclaringType == typeof(string));

Try / catch

try { var q = ctx.Users.Select(u => Client(u.Name)).ToList(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("could not be translated")) {
    // Force client evaluation by materializing first.
    var data = ctx.Users.Select(u => new { u.Name }).AsEnumerable().Select(u => Client(u.Name)).ToList();
}

Prevention

When it happens

Trigger: A Select/Where/etc. projection references a parameter or method that cannot be translated to SQL (e.g. a delegate parameter, an unmapped property, calling arbitrary .NET methods in the projection). Triggered specifically in the index-based binding fallback path where a ParameterExpression reaches translation.

Common situations: Projecting a closure variable into the query; calling a custom C# method in Select; referencing a non-mapped property; using .NET APIs with no SQL translation (e.g. complex string/date manipulation); upgrading EF where a previously client-evaluated construct now throws.

Related errors


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