dotnet/efcore · error · NotImplementedException

Power over non-double operands

Error message

Power over non-double operands

What it means

Thrown by VisitBinary for ExpressionType.Power when operands are not both double. Only double operands are supported (translated to a Math.Pow call); other numeric types are not auto-converted. Part of EF Core's LINQ-to-C# syntax translation.

Source

Thrown at src/EFCore.Design/Query/Internal/LinqToCSharpSyntaxTranslator.cs:337

            case ExpressionType.OrAssign:
                return VisitAssignment(binary, SyntaxKind.OrAssignmentExpression);
            case ExpressionType.LeftShiftAssign:
                return VisitAssignment(binary, SyntaxKind.LeftShiftAssignmentExpression);
            case ExpressionType.RightShiftAssign:
                return VisitAssignment(binary, SyntaxKind.RightShiftAssignmentExpression);
            case ExpressionType.ExclusiveOrAssign:
                return VisitAssignment(binary, SyntaxKind.ExclusiveOrAssignmentExpression);

            case ExpressionType.Power when binary.Left.Type == typeof(double) && binary.Right.Type == typeof(double):
                return Visit(
                    Expression.Call(
                        _mathPowMethod ??= typeof(Math).GetMethod(
                            nameof(Math.Pow), BindingFlags.Static | BindingFlags.Public, [typeof(double), typeof(double)])!,
                        binary.Left,
                        binary.Right));

            case ExpressionType.Power:
                throw new NotImplementedException("Power over non-double operands");

            case ExpressionType.PowerAssign:
                return Visit(
                    Expression.Assign(
                        binary.Left,
                        Expression.Power(
                            binary.Left,
                            binary.Right)));
        }

        var liftedStatementOrigPosition = _liftedState.Statements.Count;
        var left = Translate<ExpressionSyntax>(binary.Left);
        var liftedStatementLeftPosition = _liftedState.Statements.Count;
        var right = Translate<ExpressionSyntax>(binary.Right);

        // If both sides were lifted, we don't need to do anything special. Same if the left side was lifted.
        // But if the right side was lifted and the left wasn't, then in order to preserve evaluation order we need to lift the left side
        // out as well, otherwise the right side gets evaluated before the left.

View on GitHub (pinned to dbf9771522)

Solutions

  1. Cast both operands to double before constructing Expression.Power.
  2. Use Math.Pow directly with double operands.

Example fix

// before
Expression.Power(leftInt, rightInt)
// after
Expression.Power(
    Expression.Convert(leftInt, typeof(double)),
    Expression.Convert(rightInt, typeof(double)))
Defensive patterns

Strategy: validation

Validate before calling

// Validate Power operands are double before building the expression
if (binary.NodeType == ExpressionType.Power
    && (binary.Left.Type != typeof(double) || binary.Right.Type != typeof(double)))
{
    binary = Expression.Power(
        Expression.Convert(binary.Left, typeof(double)),
        Expression.Convert(binary.Right, typeof(double)));
}

Prevention

When it happens

Trigger: An expression tree containing Expression.Power (or PowerAssign) with non-double operand types such as int, float, or decimal.

Common situations: Building expression trees programmatically with Expression.Power over integers; query translators emitting Power with the wrong operand types.

Related errors


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