dotnet/efcore · error · NotSupportedException

Async lambdas are not supported

Error message

Async lambdas are not supported

What it means

Thrown by CSharpToLinqTranslator when a Roslyn lambda node being turned into a LINQ expression tree has the 'async' keyword (lambda.AsyncKeyword is not SyntaxKind.None). Expression trees cannot represent async control flow, so the translator rejects async lambdas outright during the lambda visit.

Solutions

  1. Remove the 'async' keyword from the lambda; do synchronous work or materialize results before awaiting.
  2. Move the async work out of the expression tree: project on the client after ToListAsync/ToArrayAsync rather than inside the IQueryable Select/Where.
  3. If awaiting server-side operations is required, restructure to call EF async APIs (ToListAsync) instead of embedding await inside the lambda.

Example fix

// before
var names = await db.Users
    .Select(async u => await FormatAsync(u.Name))
    .ToListAsync();

// after
var users = await db.Users.ToListAsync();
var names = await Task.WhenAll(users.Select(u => FormatAsync(u.Name)));
Defensive patterns

Strategy: validation

Validate before calling

// Reject async lambdas before translation.
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp;

bool IsSyncExpressionLambda(AnonymousFunctionExpressionSyntax lambda)
    => lambda.AsyncKeyword.IsKind(SyntaxKind.None)
       && lambda.ExpressionBody is not null;

if (!IsSyncExpressionLambda(lambdaNode))
    throw new InvalidOperationException("Async lambdas cannot be translated; do async work outside the query.");

Prevention

When it happens

Trigger: An EF query passed through CSharpToLinqTranslator contains a lambda marked async, e.g. db.Users.Select(async u => await FetchAsync(u)) reaching VisitLambdaExpression where the AsyncKeyword token is present.

Common situations: Mixing async/await into an IQueryable LINQ operator that takes an Expression<Func<...>> (the C# compiler usually blocks this, but the translator parses raw source, so a manual Roslyn-constructed tree or a delegate overload can still reach this path); or a source-generator build of a project that mistakenly authored an async lambda in the query expression.

Related errors


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

Appendix: source

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

    /// </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()
        };

        var translatedParameters = new List<ParameterExpression>();
        foreach (var parameter in lambdaParameters)
        {
            if (_semanticModel.GetDeclaredSymbol(parameter) is not { } parameterSymbol
                || ResolveType(parameterSymbol.Type) is not { } parameterType)
            {
                throw new InvalidOperationException("Could not found symbol for parameter lambda: " + parameter);
            }

View on GitHub (pinned to 3a2006ef56)