dotnet/efcore · error · InvalidOperationException

Encountered {SyntaxKind.AsExpression} with non-constant type

Error message

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

What it means

In the `SyntaxKind.AsExpression` arm of `VisitBinaryExpression`, the translator needs the right operand to be a `ConstantExpression` holding a `Type` (plain `x as SomeType`). Any non-constant right side throws `InvalidOperationException`; only the simple cast-or-null form is translatable.

Source

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

            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>
    public override Expression VisitCastExpression(CastExpressionSyntax cast)
        => Convert(Visit(cast.Expression), ResolveType(cast.Type));

    /// <summary>
    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to

View on GitHub (pinned to dbf9771522)

Solutions

  1. Keep the `as` expression as a plain type conversion (`x as TargetType`).
  2. If the right side is dynamic, hoist it out of the query.

Example fix

// before
var q = ctx.Items.Where(i => (i.Payload as varType) != null);
// after
var q = ctx.Items.Where(i => i.Payload is TargetType).Select(i => (TargetType)i.Payload);
Defensive patterns

Strategy: validation

Validate before calling

// Reject anything other than a plain `as Type` before translation.
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp;
bool unsupportedAs = node.DescendantNodes().OfType<BinaryExpressionSyntax>()
    .Any(b => b.IsKind(SyntaxKind.AsExpression)
              && !(b.Right is PredefinedTypeSyntax || b.Right is IdentifierNameSyntax || b.Right is QualifiedNameSyntax));
if (unsupportedAs)
    throw new NotSupportedException("Only plain `x as T` conversions are supported in precompiled queries.");

translator.Translate(node, semanticModel);

Try / catch

try { translator.Translate(node, semanticModel); }
catch (InvalidOperationException ex) when (ex.Message.Contains("AsExpression") && ex.Message.Contains("non-constant type"))
{ /* rewrite as a plain type conversion */ }

Prevention

When it happens

Trigger: A precompiled query using `as` with something other than a bare type reference, or where the translator cannot fold the right side to a constant `Type`.

Common situations: Complex generics or pattern-based `as` usage inside a query; usually the compiler keeps `as Type` simple, so this is rare in hand-written code but possible with generated/synthesized trees.

Related errors


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