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

  1. Rewrite the expression to use a supported unary node type or an equivalent binary/method-call form.
  2. Avoid arithmetic-assignment unary nodes (e.g. AddAssign-like unary forms) in translated trees.
  3. 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

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


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 initializer

View on GitHub (pinned to 3a2006ef56)