dotnet/efcore · error · NotSupportedException
Unsupported syntax node of type
Error message
Unsupported syntax node of type '{node.GetType()}': {node} What it means
Thrown by DefaultVisit — the catch-all override that fires for ANY C# syntax node type that does not have a specific Visit override in the translator. This is the ultimate fallback: if the translator encounters a syntax construct it has no handler for (no VisitXxx override matched), DefaultVisit throws NotSupportedException. The message includes the node's runtime type and its full text for diagnosis.
Solutions
- Identify the unsupported construct from the error message (it includes the node type name) and rewrite it using a more basic form the translator handles.
- Replace switch expressions/patterns with if-else chains or ternary operators.
- Replace conditional access (x?.Y) with explicit null checks (x != null ? x.Y : null).
- Replace tuple syntax with anonymous objects or separate variable bindings.
- Replace checked/unchecked with unchecked method calls or remove the checked context.
- If the construct is essential, exclude the query from precompilation or file an EF Core issue for support.
- Check the EF Core release notes — newer versions may have added support for the construct you're using.
Example fix
// before — switch expression (DefaultVisit catch-all)
var query = ctx.Orders.Select(o => o.Status switch {
Status.Pending => 0,
Status.Shipped => 1,
_ => 2
});
// after — conditional expression
var query = ctx.Orders.Select(o =>
o.Status == Status.Pending ? 0 :
o.Status == Status.Shipped ? 1 : 2); Defensive patterns
Strategy: validation
Validate before calling
// Before precompiling, identify syntax node types that will hit DefaultVisit
var knownOverrides = new HashSet<string> {
nameof(CSharpSyntaxVisitor<Expression>.VisitBinaryExpression),
nameof(CSharpSyntaxVisitor<Expression>.VisitInvocationExpression),
nameof(CSharpSyntaxVisitor<Expression>.VisitMemberAccessExpression),
nameof(CSharpSyntaxVisitor<Expression>.VisitObjectCreationExpression),
nameof(CSharpSyntaxVisitor<Expression>.VisitSimpleLambdaExpression),
nameof(CSharpSyntaxVisitor<Expression>.VisitParenthesizedLambdaExpression),
nameof(CSharpSyntaxVisitor<Expression>.VisitLiteralExpression),
// ... (all overridden Visit methods in CSharpToLinqTranslator)
};
// Any node whose CSharpSyntaxVisitor dispatches to DefaultVisit will trigger the error
var unhandledNodes = querySyntaxTree.DescendantNodes()
.Where(n => IsDispatchedToDefaultVisit(n)); // requires knowing the visitor's override set
if (unhandledNodes.Any())
ReportError($"Unsupported syntax node(s): {string.Join(", ", unhandledNodes.Select(n => n.GetType().Name))}"); Try / catch
// If invoking the translator programmatically:
try { var expr = translator.Translate(node, semanticModel); }
catch (NotSupportedException ex) when (ex.Message.Contains("Unsupported syntax node"))
{
// Log the unsupported construct and fall back to runtime compilation
LogPrecompileSkipped(node, ex.Message);
// The query will compile normally at runtime without precompilation
} Prevention
- Write precompiled queries using only basic C# constructs: property access, arithmetic, ternary operators, and standard method calls.
- Avoid modern C# features (switch expressions, patterns, tuples, ranges) inside precompiled query lambdas until confirmed supported.
- Replace conditional access (x?.Y) with explicit null checks (x != null ? x.Y : null).
- Replace pattern matching with if-else or ternary chains.
- Check EF Core release notes for newly supported syntax constructs with each version.
- Run precompilation in CI to catch unsupported constructs early.
- Keep precompiled query code deliberately simple and separate complex logic into translatable helper methods.
When it happens
Trigger: Any C# expression construct not explicitly handled by a Visit override triggers this. Examples include: checked/unchecked expressions, sizeof expressions, stackalloc expressions, default value expressions in some forms, tuple expressions, switch expressions, switch statements, pattern matching (is-pattern), conditional access (?.) in certain positions, range expressions, interpolated string handlers in complex forms, ref expressions, yield expressions, local function declarations, lock/fixed/using statements, and any new C# language feature not yet supported by the translator.
Common situations: Using newer C# language features (C# 10-13+) inside precompiled queries before the translator is updated to support them; using pattern matching (switch expressions, `is` patterns) in query predicates; using tuple deconstruction in projections; using checked arithmetic; using conditional access expressions (`entity?.Property`); using interpolation with complex format providers. The most common trigger is simply writing modern idiomatic C# in a query that gets precompiled.
Related errors
- ArrayCreation: multi-dimensional array
- ObjectCreation: non-assignment initializer expression of…
- Could not find symbol for method invocation
- Could not find symbol for typeof() expression
- Couldn't find single Add method on type
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/f9d6b44ff5de897e.
Report an issue: GitHub.
Appendix: source
Thrown at src/EFCore.Design/Query/Internal/CSharpToLinqTranslator.cs:1026
{
if (_semanticModel.GetSymbolInfo(typeOf.Type).Symbol is not ITypeSymbol typeSymbol)
{
throw new InvalidOperationException(
"Could not find symbol for typeof() expression: " + typeOf);
}
var type = ResolveType(typeSymbol);
return Constant(type, typeof(Type));
}
/// <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 DefaultVisit(SyntaxNode node)
=> throw new NotSupportedException($"Unsupported syntax node of type '{node.GetType()}': {node}");
private Expression VisitLambdaExpression(AnonymousFunctionExpressionSyntax lambda, Type? expectedType = null)
{
if (lambda.ExpressionBody is null)
{
throw new NotSupportedException("Lambda with null expression body");
}
if (lambda.Modifiers.Any())
{
throw new NotSupportedException("Lambda with modifiers not supported: " + lambda.Modifiers);
}
if (!lambda.AsyncKeyword.IsKind(SyntaxKind.None))
{
throw new NotSupportedException("Async lambdas are not supported");
}
View on GitHub (pinned to 3a2006ef56)