devlooped/moq · error · NotSupportedException
The equals ("==" or "=" in VB) and the conditional 'and'…
Error message
The equals ("==" or "=" in VB) and the conditional 'and' ("&&" or "AndAlso" in VB) operators are the only ones supported in the query specification expression. Unsupported expression: {0} What it means
Moq's LINQ-to-Mocks (Mock.Of / query syntax) translates the query expression into mock setups via MockSetupsBuilder.VisitBinary. Inside a specification, only Equal (==) and AndAlso (&&) binary operators can be translated; anything else (>, <, !=, ||, +, etc.) throws NotSupportedException. This is a deliberate limitation of the simple LINQ provider, not a bug.
Solutions
- Rewrite the predicate using only == and && (e.g. replace x > 3 with an exact-value match).
- Invert logic: replace 'a != b' with 'a == expected' where possible.
- Fall back to classic setup API: mock.Setup(f => f.Bar).Returns(...).Callback(...) or Setup with It.Is<T>(predicate) matchers, which support arbitrary predicates.
- Use a callback/Returns delegate for complex logic instead of the LINQ query expression.
Example fix
// before
var foo = Mock.Of<IFoo>(f => f.Bar > 3);
// after
var foo = Mock.Of<IFoo>(f => f.Bar == 4);
// or
var mock = new Mock<IFoo>();
mock.Setup(f => f.Bar).Callback(() => { /* complex logic */ }).Returns(5); Defensive patterns
Strategy: validation
Validate before calling
// Restrict Mock.Of predicates to == and &&: // OK: f => f.A == 1 && f.B == "x" // NOT OK: f => f.A > 1 || f.B != "x" -> use mock.Setup + It.Is instead
Try / catch
try { var foo = Mock.Of<IFoo>(predicate); }
catch (NotSupportedException) { var mock = new Mock<IFoo>(); mock.Setup(...); foo = mock.Object; } Prevention
- Remember LINQ-to-Mocks supports only == and && inside the specification.
- For inequalities, ranges, or || conditions, use mock.Setup with It.Is<T>(predicate) matchers.
- Keep Mock.Of predicates trivial; move complex conditions into setup API.
When it happens
Trigger: var foo = Mock.Of<IFoo>(f => f.Bar > 3), f => f.Name != "x", or f => f.A || f.B — any query-spec binary node whose NodeType is neither Equal nor AndAlso when stackIndex > 0.
Common situations: Writing convenient range or inequality filters in Mock.Of predicates; using || for 'or' conditions; after migrating from a full LINQ provider and assuming all operators are supported.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- LINQ method ' ' not supported.
- Type to mock ( ) must be an interface, a delegate, or a…
- A matching constructor for the given arguments was not…
- It is impossible to call the provided strongly-typed…
- ArgumentNullException: Value cannot be null. (Parameter…
AI-assisted analysis of devlooped/moq@89a5be629c (2026-09-16).
Data as JSON: /api/errors/55afd36e08d7722d.
Report an issue: GitHub.
Appendix: source
Thrown at src/Moq/Linq/MockSetupsBuilder.cs:32
{
class MockSetupsBuilder : ExpressionVisitor
{
static readonly string[] queryableMethods = new[] { "First", "Where", "FirstOrDefault" };
static readonly string[] unsupportedMethods = new[] { "All", "Any", "Last", "LastOrDefault", "Single", "SingleOrDefault" };
int stackIndex;
int quoteDepth;
public MockSetupsBuilder()
{
}
protected override Expression VisitBinary(BinaryExpression node)
{
if (this.stackIndex > 0)
{
if (node.NodeType != ExpressionType.Equal && node.NodeType != ExpressionType.AndAlso)
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Resources.LinqBinaryOperatorNotSupported, node.ToStringFixed()));
if (node.NodeType == ExpressionType.Equal)
{
// TODO: throw if a matcher is used on either side of the expression.
//ThrowIfMatcherIsUsed(
// Account for the inverted assignment/querying like "false == foo.IsValid" scenario
if (node.Left.NodeType == ExpressionType.Constant)
// Invert left & right nodes in this case.
return ConvertToSetup(node.Right, node.Left) ?? base.VisitBinary(node);
else
// Perform straight conversion where the right-hand side will be the setup return value.
return ConvertToSetup(node.Left, node.Right) ?? base.VisitBinary(node);
}
}
return base.VisitBinary(node);
}View on GitHub (pinned to 89a5be629c)