dotnet/efcore · error · NotSupportedException
Encountered non-quotable expression of type
Error message
Encountered non-quotable expression of type {node.GetType()} when translating expression tree to C# What it means
Thrown by VisitExtension when an extension Expression node is encountered that is not an EntityQueryRootExpression. The translator special-cases EntityQueryRootExpression (rendering it as context.Set<TEntity>()), but any other extension node type is considered non-quotable into C# and throws NotSupportedException with the node's runtime type.
Solutions
- Remove the unsupported extension node from the query or replace it with a standard expression EF can translate.
- If the node is an EF-internal query root, ensure it is an EntityQueryRootExpression so it renders as context.Set<T>().
- Report the node type to EF if it appears in a normal query (possible translator gap).
Defensive patterns
Strategy: validation
Validate before calling
// Reject non-EntityQueryRootExpression extension nodes
static bool HasUnknownExtension(Expression e)
{
bool bad = false;
new ExtensionChecker { OnBad = () => bad = true }.Visit(e);
return bad;
}
class ExtensionChecker : ExpressionVisitor
{
public Action OnBad;
protected override Expression VisitExtension(Expression node)
{
if (node is not EntityQueryRootExpression) OnBad();
return base.VisitExtension(node);
}
} Type guard
static bool IsTranslatableExtension(Expression node) => node is EntityQueryRootExpression;
Try / catch
try { var csharp = translator.Translate(expr); }
catch (NotSupportedException ex) when (ex.Message.Contains("non-quotable expression"))
{ throw new InvalidOperationException($"Query contains an extension node type EF cannot translate to C#: {ex.Message}.", ex); } Prevention
- Do not introduce custom Expression subclasses into EF-translated trees.
- Ensure query roots are EntityQueryRootExpression.
- Report unknown EF-internal extension nodes that appear in normal queries.
When it happens
Trigger: An expression tree passed to the translator contains a custom or EF-internal Expression extension type that is not EntityQueryRootExpression (e.g. a proprietary query root, a specialized EF extension node, or a user-defined Expression subclass).
Common situations: A precompiled query references an extension expression the translator has not been taught to handle; mixing in provider-specific extension nodes; upgrading EF where a new internal extension node appears before translator support is added.
Related errors
- Missing default arm for switch expression
- Switch with non-null comparison method
- Unary node with non-null method
- Unnamed captured variable
- Unsupported LINQ unary node
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/61187ff70779a3b6.
Report an issue: GitHub.
Appendix: source
Thrown at src/EFCore.Design/Query/Internal/LinqToCSharpSyntaxTranslator.cs:2691
/// <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>
protected override Expression VisitExtension(Expression node)
{
// TODO: Remove any EF-specific code from this visitor (extend if needed)
// TODO: Hack mode. Visit the expression beforehand to replace EntityQueryRootExpression with context.Set<>(), or receive it in this visitor as a replacement or something.
if (node is EntityQueryRootExpression entityQueryRoot)
{
// TODO: STET
Result = ParseExpression($"context.Set<{entityQueryRoot.EntityType.ClrType.Name}>()");
return node;
}
throw new NotSupportedException(
$"Encountered non-quotable expression of type {node.GetType()} when translating expression tree to C#");
}
private ArgumentSyntax[] TranslateMethodArguments(ParameterInfo[] parameters, IReadOnlyList<Expression> arguments)
{
var translatedExpressions = TranslateList(arguments);
var translatedArguments = new ArgumentSyntax[arguments.Count];
for (var i = 0; i < translatedExpressions.Length; i++)
{
var parameter = parameters[i];
var argument = Argument(translatedExpressions[i]);
if (parameter.IsOut)
{
argument = argument.WithRefKindKeyword(Token(SyntaxKind.OutKeyword));
}
else if (parameter.IsIn)View on GitHub (pinned to 3a2006ef56)