dotnet/efcore · error · ArgumentOutOfRangeException
Unsupported LINQ unary node
Error message
Unsupported LINQ unary node: {unary.NodeType} What it means
Thrown by VisitUnary as the default case of its NodeType switch when a UnaryExpression node type is not among the handled set (Negate, NegateChecked, Not, OnesComplement, IsFalse, IsTrue, ArrayLength, Convert, ConvertChecked, Throw, TypeAs, Quote, UnaryPlus, Unbox, Increment, Decrement, and the increment/decrement assignment types). It is an ArgumentOutOfRangeException indicating the node type is simply not implemented by the translator.
Solutions
- Rewrite the expression to use a supported unary node type or an equivalent binary/method-call form.
- Avoid arithmetic-assignment unary nodes (e.g. AddAssign-like unary forms) in translated trees.
- Check the supported NodeType list in VisitUnary and restructure accordingly.
Defensive patterns
Strategy: validation
Validate before calling
static readonly HashSet<ExpressionType> SupportedUnary = new()
{ ExpressionType.Negate, ExpressionType.NegateChecked, ExpressionType.Not, ExpressionType.OnesComplement,
ExpressionType.IsFalse, ExpressionType.IsTrue, ExpressionType.ArrayLength, ExpressionType.Convert,
ExpressionType.ConvertChecked, ExpressionType.Throw, ExpressionType.TypeAs, ExpressionType.Quote,
ExpressionType.UnaryPlus, ExpressionType.Unbox, ExpressionType.Increment, ExpressionType.Decrement,
ExpressionType.PostIncrementAssign, ExpressionType.PostDecrementAssign, ExpressionType.PreIncrementAssign, ExpressionType.PreDecrementAssign };
static bool UsesOnlySupportedUnary(Expression e) { /* visit UnaryExpression nodes, check SupportedUnary.Contains(u.NodeType) */ return true; } Type guard
static bool IsSupportedUnaryType(ExpressionType t) => SupportedUnary.Contains(t);
Try / catch
try { var csharp = translator.Translate(expr); }
catch (ArgumentOutOfRangeException ex) when (ex.Message.Contains("Unsupported LINQ unary node"))
{ throw new InvalidOperationException("Query uses an unimplemented unary node type.", ex); } Prevention
- Check node types against the supported set before translating.
- Rewrite arithmetic-assignment unary nodes as binary/method-call expressions.
- Keep query expressions simple to stay within supported shapes.
When it happens
Trigger: An expression tree contains a UnaryExpression whose NodeType is outside the enumerated supported set (for example an assignment-related or arithmetic-assignment unary type the translator never added), and the tree reaches the C# translator.
Common situations: Programmatic construction of unusual UnaryExpression node types; expression trees produced by reflection over arithmetic-assignment operations; edge-case LINQ shapes in precompiled queries.
Related errors
- Unary node with non-null method
- Encountered non-quotable expression of type
- Missing default arm for switch expression
- Switch with non-null comparison method
- Unnamed captured variable
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/5c922e93becd522c.
Report an issue: GitHub.
Appendix: source
Thrown at src/EFCore.Design/Query/Internal/LinqToCSharpSyntaxTranslator.cs:2513
ExpressionType.IsTrue => operand,
ExpressionType.ArrayLength => _g.MemberAccessExpression(operand, "Length"),
ExpressionType.Convert => ParenthesizedExpression((ExpressionSyntax)_g.ConvertExpression(Generate(unary.Type), operand)),
ExpressionType.ConvertChecked =>
ParenthesizedExpression((ExpressionSyntax)_g.ConvertExpression(Generate(unary.Type), operand)),
ExpressionType.Throw when unary.Type == typeof(void) => _g.ThrowStatement(operand),
ExpressionType.Throw => _g.ThrowExpression(operand),
ExpressionType.TypeAs => BinaryExpression(SyntaxKind.AsExpression, operand, Generate(unary.Type)),
ExpressionType.Quote => operand,
ExpressionType.UnaryPlus => PrefixUnaryExpression(SyntaxKind.UnaryPlusExpression, operand),
ExpressionType.Unbox => operand,
ExpressionType.Increment => Translate(Expression.Add(unary.Operand, Expression.Constant(1))),
ExpressionType.Decrement => Translate(Expression.Subtract(unary.Operand, Expression.Constant(1))),
ExpressionType.PostIncrementAssign => PostfixUnaryExpression(SyntaxKind.PostIncrementExpression, operand),
ExpressionType.PostDecrementAssign => PostfixUnaryExpression(SyntaxKind.PostDecrementExpression, operand),
ExpressionType.PreIncrementAssign => PrefixUnaryExpression(SyntaxKind.PreIncrementExpression, operand),
ExpressionType.PreDecrementAssign => PrefixUnaryExpression(SyntaxKind.PreDecrementExpression, operand),
_ => throw new ArgumentOutOfRangeException("Unsupported LINQ unary node: " + unary.NodeType)
};
return unary;
}
/// <inheritdoc />
protected override Expression VisitMemberInit(MemberInitExpression memberInit)
{
var objectCreation = Translate<ObjectCreationExpressionSyntax>(memberInit.NewExpression);
List<MemberListBinding>? incompatibleListBindings = null;
var initializerExpressions = new List<AssignmentExpressionSyntax>(memberInit.Bindings.Count);
foreach (var binding in memberInit.Bindings)
{
// C# collection initialization syntax only works when Add is called on an IEnumerable, but LINQ supports arbitrary add
// methods. Skip these, we'll add them later outside the initializerView on GitHub (pinned to 3a2006ef56)