dotnet/efcore · error · NotSupportedException

Lambda with null expression body

Error message

Lambda with null expression body

What it means

Thrown as NotSupportedException by VisitLambdaExpression when a lambda expression has a null ExpressionBody — meaning it is a statement lambda (a lambda with a block body containing statements) rather than an expression lambda (a single expression body). The translator can only convert expression-bodied lambdas into LINQ expression-tree LambdaExpressions. Statement lambdas would require full statement-to-expression-tree translation, which is not supported.

Solutions

  1. Rewrite the statement lambda as an expression lambda: extract any local variables into the expression using let-style chaining or inline them, and use ternary operators instead of if statements.
  2. Move complex logic that requires statements into a separate helper method and call it from the expression lambda (ensure the method is translatable).
  3. Replace if-else logic with conditional (ternary) expressions: `b => b.Id > 0 ? b.Name : null`.
  4. Replace local variable computations with method chaining: instead of `b => { var x = b.Salary * 2; return x > 1000; }` use `b => b.Salary * 2 > 1000`.
  5. Remove any debugging code (Console.WriteLine, logging) from lambdas inside precompiled queries.

Example fix

// before — statement lambda
var query = ctx.Blogs.Where(b =>
{
    var adjusted = b.Score * b.Weight;
    return adjusted > 100;
});

// after — expression lambda
var query = ctx.Blogs.Where(b => b.Score * b.Weight > 100);
Defensive patterns

Strategy: validation

Validate before calling

// Before precompiling, scan for statement lambdas (block-bodied lambdas)
var statementLambdas = querySyntaxTree.DescendantNodes()
    .Where(n => n is SimpleLambdaExpressionSyntax or ParenthesizedLambdaExpressionSyntax)
    .Cast<AnonymousFunctionExpressionSyntax>()
    .Where(l => l.ExpressionBody is null); // null ExpressionBody means block body
if (statementLambdas.Any())
    ReportError("Statement lambdas (block bodies) are not supported in precompiled queries — use expression lambdas");

Type guard

// Type guard to distinguish expression lambdas from statement lambdas (Roslyn CSharpSyntaxVisitor level)
// ExpressionBody is non-null for expression lambdas, null for statement lambdas
static bool IsExpressionLambda(AnonymousFunctionExpressionSyntax lambda)
    => lambda.ExpressionBody is not null;

// Usage before precompilation:
// if (!IsExpressionLambda(lambdaNode)) skipPrecompilation(lambdaNode);

Prevention

When it happens

Trigger: A precompiled query contains a lambda with a statement block body instead of a single expression: `ctx.Blogs.Where(b => { var x = b.Id + 1; return x > 10; })`. The translator's VisitLambdaExpression checks `lambda.ExpressionBody is null` (which is true for block-bodied lambdas) and throws NotSupportedException.

Common situations: Developers who use statement lambdas for complex logic inside LINQ calls; refactoring expression lambdas into statement lambdas during debugging (adding logging, breakpoints); multi-line predicates that were written as blocks for readability; code produced by refactoring tools that convert expressions to statement blocks; developers unfamiliar with the expression-tree limitation on statement lambdas.

Related errors


AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11). Data as JSON: /api/errors/50e7f181d3b07b3c. Report an issue: GitHub.

Appendix: source

Thrown at src/EFCore.Design/Query/Internal/CSharpToLinqTranslator.cs:1032

        var type = ResolveType(typeSymbol);
        return Constant(type, typeof(Type));
    }

    /// <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 DefaultVisit(SyntaxNode node)
        => throw new NotSupportedException($"Unsupported syntax node of type '{node.GetType()}': {node}");

    private Expression VisitLambdaExpression(AnonymousFunctionExpressionSyntax lambda, Type? expectedType = null)
    {
        if (lambda.ExpressionBody is null)
        {
            throw new NotSupportedException("Lambda with null expression body");
        }

        if (lambda.Modifiers.Any())
        {
            throw new NotSupportedException("Lambda with modifiers not supported: " + lambda.Modifiers);
        }

        if (!lambda.AsyncKeyword.IsKind(SyntaxKind.None))
        {
            throw new NotSupportedException("Async lambdas are not supported");
        }

        var lambdaParameters = lambda switch
        {
            SimpleLambdaExpressionSyntax simpleLambda => SyntaxFactory.SingletonSeparatedList(simpleLambda.Parameter),
            ParenthesizedLambdaExpressionSyntax parenthesizedLambda => parenthesizedLambda.ParameterList.Parameters,

            _ => throw new UnreachableException()

View on GitHub (pinned to 3a2006ef56)