dotnet/efcore · error · InvalidOperationException

Unhandled expression '{expression}' of type '{expressionType

Error message

Unhandled expression '{expression}' of type '{expressionType}' encountered in '{visitor}'.

What it means

Thrown by QuerySqlGenerator's main expression switch (the default case) when it encounters a SQL expression type it does not have a Visit method for. The QuerySqlGenerator handles known SqlExpression subtypes (SqlBinaryExpression, SqlConstantExpression, etc.); any unrecognized Expression falls through to this throw. This is almost always a provider bug — the translator declared an expression as supported but the SQL generator can't emit it.

Source

Thrown at src/EFCore.Relational/Query/QuerySqlGenerator.cs:157

            RightJoinExpression e => VisitRightJoin(e),
            FullJoinExpression e => VisitFullJoin(e),
            RowNumberExpression e => VisitRowNumber(e),
            RowValueExpression e => VisitRowValue(e),
            ScalarSubqueryExpression e => VisitScalarSubquery(e),
            SelectExpression e => VisitSelect(e),
            SqlBinaryExpression e => VisitSqlBinary(e),
            SqlConstantExpression e => VisitSqlConstant(e),
            SqlFragmentExpression e => VisitSqlFragment(e),
            SqlFunctionExpression e => VisitSqlFunction(e),
            SqlParameterExpression e => VisitSqlParameter(e),
            SqlUnaryExpression e => VisitSqlUnary(e),
            TableExpression e => VisitTable(e),
            UnionExpression e => VisitUnion(e),
            UpdateExpression e => VisitUpdate(e),
            JsonScalarExpression e => VisitJsonScalar(e),
            ValuesExpression e => VisitValues(e),

            _ => throw new InvalidOperationException(
                RelationalStrings.UnhandledExpressionInVisitor(expression, expression.GetType(), nameof(QuerySqlGenerator))),
        };

    /// <summary>
    ///     Generates SQL for an arbitrary fragment.
    /// </summary>
    /// <param name="sqlFragmentExpression">The <see cref="SqlFragmentExpression" /> for which to generate SQL.</param>
    protected virtual Expression VisitSqlFragment(SqlFragmentExpression sqlFragmentExpression)
    {
        _relationalCommandBuilder.Append(sqlFragmentExpression.Sql);

        return sqlFragmentExpression;
    }

    private static bool TryUnwrapBareSetOperation(SelectExpression selectExpression, [NotNullWhen(true)] out SetOperationBase? setOperation)
    {
        if (selectExpression is
            {

View on GitHub (pinned to 3a2006ef56)

Solutions

  1. If using a third-party provider, report the issue to the provider maintainer with the expression type from the error message.
  2. If using EF Core directly, file an issue at https://github.com/dotnet/efcore with the query and full exception details.
  3. Try reformulating the query to avoid the expression pattern that triggers the unhandled type.
Defensive patterns

Strategy: try-catch

Try / catch

try
{
    var result = await query.ToListAsync();
}
catch (InvalidOperationException ex) when (ex.Message.Contains("Unhandled expression"))
{
    logger.LogError(ex, "SQL generator encountered unhandled expression type — possible provider bug");
    // Try reformulating the query to avoid the unsupported expression pattern
    throw;
}

Prevention

When it happens

Trigger: A custom EF Core provider (or an internal EF Core relational pipeline path) produces a SqlExpression-derived type that the QuerySqlGenerator's switch doesn't handle. The expression passed translation but fails at SQL generation time because no VisitXxx method exists for it.

Common situations: Third-party database provider that has incomplete SQL generation coverage. EF Core internal bug where a new SqlExpression type was added to translation but not to the generator. Using a preview or nightly EF Core build with incomplete feature implementation.

Related errors


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