dotnet/efcore · error · NotImplementedException
Unary node with non-null method
Error message
Unary node with non-null method
What it means
Thrown by VisitUnary when a UnaryExpression has a non-null Method that is not a conversion operator (op_Implicit/op_Explicit) and is neither HideBySig nor SpecialName. The translator only knows how to render built-in unary operators and user-defined conversions; any other method-backed unary operation (e.g. a custom overloaded unary operator that does not fit the recognised shapes) is unimplemented and throws NotImplementedException.
Solutions
- Avoid using custom method-backed unary operators in expressions handed to the C# translator.
- Replace the operator call with an equivalent built-in unary expression or a method call expression.
- If it is a conversion, ensure the method is named op_Implicit or op_Explicit so it is recognised.
Example fix
// before: custom unary operator with Method set to a non-conversion MethodInfo // after: express the operation as a method call or built-in unary node without a custom Method
Defensive patterns
Strategy: validation
Validate before calling
// Reject unary nodes with unsupported backing methods
static bool HasUnsupportedUnaryMethod(Expression e)
{
bool bad = false;
ExpressionVisitor visitor = null!;
visitor = new ExpressionVisitorWrapper {
OnUnary = u => { if (u.Method is not null && u.Method.Name is not ("op_Implicit" or "op_Explicit") && !u.Method.IsSpecialName) bad = true; }
};
visitor.Visit(e);
return bad;
} Type guard
static bool IsTranslatableUnary(UnaryExpression u) => u.Method is null || u.Method.Name is "op_Implicit" or "op_Explicit" || u.Method.IsSpecialName || u.Method.IsHideBySig;
Try / catch
try { var csharp = translator.Translate(expr); }
catch (NotImplementedException ex) when (ex.Message.Contains("Unary node with non-null method"))
{ throw new InvalidOperationException("A unary node carries an unsupported operator method.", ex); } Prevention
- Avoid custom operator MethodInfos on unary nodes in translated trees.
- Express non-conversion operators as method calls instead.
- Keep conversion operators named op_Implicit/op_Explicit.
When it happens
Trigger: An expression tree contains a UnaryExpression whose Method is a custom operator MethodInfo that is not op_Implicit/op_Explicit, not HideBySig, and not SpecialName, and the tree is translated to C#.
Common situations: User-defined unary operators surfaced as method-backed UnaryExpressions; expression trees built by tools that attach arbitrary MethodInfo objects to unary nodes; rare custom operator overloads in value converters or computed selectors.
Related errors
- Unsupported LINQ unary node
- 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/bc1895abfefcd721.
Report an issue: GitHub.
Appendix: source
Thrown at src/EFCore.Design/Query/Internal/LinqToCSharpSyntaxTranslator.cs:2478
ExpressionType.TypeEqual
=> BinaryExpression(SyntaxKind.EqualsExpression, visitedExpression, TypeOfExpression(Generate(node.TypeOperand))),
_ => throw new ArgumentOutOfRangeException()
};
return node;
}
/// <inheritdoc />
protected override Expression VisitUnary(UnaryExpression unary)
{
if (unary.Method is not null
&& !unary.Method.IsHideBySig
&& !unary.Method.IsSpecialName
&& unary.Method.Name != "op_Implicit"
&& unary.Method.Name != "op_Explicit")
{
throw new NotImplementedException("Unary node with non-null method");
}
using var _ = ChangeContext(ExpressionContext.Expression);
var operand = Translate<ExpressionSyntax>(unary.Operand);
// TODO: Confirm what to do with the checked expression types
Result = unary.NodeType switch
{
ExpressionType.Negate => _g.NegateExpression(operand),
ExpressionType.NegateChecked => _g.NegateExpression(operand),
ExpressionType.Not when unary.Type == typeof(bool) => _g.LogicalNotExpression(operand),
ExpressionType.Not => _g.BitwiseNotExpression(operand),
ExpressionType.OnesComplement => _g.BitwiseNotExpression(operand),
ExpressionType.IsFalse => _g.LogicalNotExpression(operand),
ExpressionType.IsTrue => operand,
ExpressionType.ArrayLength => _g.MemberAccessExpression(operand, "Length"),View on GitHub (pinned to 3a2006ef56)