dotnet/efcore · error · InvalidOperationException

Encountered {SyntaxKind.IsExpression} with non-constant type

Error message

Encountered {SyntaxKind.IsExpression} with non-constant type right argument: {right}

What it means

In the `SyntaxKind.IsExpression` arm of `VisitBinaryExpression`, the translator requires the right operand to be a `ConstantExpression` whose `Value` is a `Type` (i.e. `x is SomeType`). If the right side is not a constant type it throws `InvalidOperationException`, because richer pattern-matching forms (`is int y`, `is { Length: > 0 }`) cannot be represented.

Source

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

            SyntaxKind.ExclusiveOrExpression when left.Type.IsEnum || right.Type.IsEnum
                => Convert(
                    ExclusiveOr(Convert(left, left.Type.GetEnumUnderlyingType()), Convert(right, right.Type.GetEnumUnderlyingType())),
                    left.Type),

            SyntaxKind.BitwiseOrExpression => Or(left, right),
            SyntaxKind.BitwiseAndExpression => And(left, right),
            SyntaxKind.ExclusiveOrExpression => ExclusiveOr(left, right),

            SyntaxKind.EqualsExpression => Equal(left, right),
            SyntaxKind.NotEqualsExpression => NotEqual(left, right),
            SyntaxKind.LessThanExpression => LessThan(left, right),
            SyntaxKind.LessThanOrEqualExpression => LessThanOrEqual(left, right),
            SyntaxKind.GreaterThanExpression => GreaterThan(left, right),
            SyntaxKind.GreaterThanOrEqualExpression => GreaterThanOrEqual(left, right),
            SyntaxKind.IsExpression => TypeIs(
                left, right is ConstantExpression { Value: Type type }
                    ? type
                    : throw new InvalidOperationException(
                        $"Encountered {SyntaxKind.IsExpression} with non-constant type right argument: {right}")),
            SyntaxKind.AsExpression => TypeAs(
                left, right is ConstantExpression { Value: Type type }
                    ? type
                    : throw new InvalidOperationException(
                        $"Encountered {SyntaxKind.AsExpression} with non-constant type right argument: {right}")),
            SyntaxKind.CoalesceExpression => Coalesce(left, right),

            _ => throw new ArgumentOutOfRangeException($"BinaryExpressionSyntax with {binary.Kind()}")
        };
    }

    /// <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>

View on GitHub (pinned to dbf9771522)

Solutions

  1. Use a plain type test (`x is SomeType`) and follow with explicit casts/member access.
  2. Move the pattern-matching logic out of the query and apply it to materialized results.

Example fix

// before
var q = ctx.Items.Where(i => (i.Data as object) is int n && n > 0);
// after
var q = ctx.Items.Where(i => i.Data is int).Select(i => (int)i.Data).Where(n => n > 0);
Defensive patterns

Strategy: validation

Validate before calling

// Scan for non-trivial 'is' patterns the translator cannot handle.
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp;
bool unsupportedIs = node.DescendantNodes().OfType<BinaryExpressionSyntax>()
    .Any(b => b.IsKind(SyntaxKind.IsExpression)
              && !(b.Right is PredefinedTypeSyntax || b.Right is IdentifierNameSyntax || b.Right is QualifiedNameSyntax));
if (unsupportedIs)
    throw new NotSupportedException("Only plain type tests (`x is T`) are supported in precompiled queries.");

translator.Translate(node, semanticModel);

Try / catch

try { translator.Translate(node, semanticModel); }
catch (InvalidOperationException ex) when (ex.Message.Contains("IsExpression") && ex.Message.Contains("non-constant type"))
{ /* rewrite the pattern as a plain type test + casts */ }

Prevention

When it happens

Trigger: A precompiled query using C# pattern matching on the left of `is` with anything other than a bare type, e.g. `obj is int n`, `o is string { Length: > 0 }`, or a switch-expression-style `is` pattern.

Common situations: Writing modern C# patterns inside a query lambda; the compiler accepts them but the translator's expression-tree model does not.

Related errors


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