dotnet/efcore · error · InvalidOperationException

UnhandledExpressionInVisitor

UnhandledExpressionInVisitor

Error message

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

What it means

Thrown by QuerySqlGenerator.Visit (QuerySqlGenerator.cs:157) when the expression-type switch hits the default case: the SQL generator received a SqlExpression/SelectExpression subtype it has no Visit method for. The relational SQL generator enumerates every supported expression kind; anything else is untranslatable to SQL, so EF throws rather than emit malformed SQL. This usually indicates a provider bug or an unsupported expression leaking into SQL generation.

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 dbf9771522)

Solutions

  1. If you are a provider author, override the correct Visit method in your QuerySqlGenerator for the new expression type.
  2. Ensure your EF Core provider version matches (is compatible with) your EF Core runtime version.
  3. Update the provider to the latest release; report the unhandled expression type to the provider/EF team.
  4. Simplify the query to avoid the construct that produces the unsupported node, and check EF logs for the expression type in the error.

Example fix

// before (provider) - a custom SqlExpression reaches the base generator unhandled
public class MyWindowExpression : SqlExpression { ... }
// QuerySqlGenerator.Visit hits default -> UnhandledExpressionInVisitor

// after - override the visitor in your provider's QuerySqlGenerator
protected override Expression VisitExtension(Expression e) {
    return e is MyWindowExpression win ? VisitMyWindow(win) : base.VisitExtension(e);
}
private Expression VisitMyWindow(MyWindowExpression e) { /* emit SQL */ return e; }
Defensive patterns

Strategy: validation

Validate before calling

// Provider: ensure your QuerySqlGenerator handles every expression type your translation emits.
protected override Expression VisitExtension(Expression e)
    => e is MyCustomSqlExpression c ? VisitCustom(c) : base.VisitExtension(e);

Prevention

When it happens

Trigger: A custom or provider-specific SqlExpression reaches the base QuerySqlGenerator without the provider having overridden the appropriate Visit method. Triggered by providers that introduce new expression types but don't teach the SQL generator to emit them, or by query shapes that surface an unexpected node.

Common situations: Database provider version mismatch (provider emits a node the base generator doesn't know); third-party EF extensions introducing custom SQL expressions; EF Core upgrade where a new expression type was added but the provider wasn't updated; bugs producing unexpected expression trees.

Related errors


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