devlooped/moq · error · NotSupportedException

Resources.UnsupportedExpression (formatted with…

Error message

Resources.UnsupportedExpression (formatted with originalExpression)

What it means

MatcherFactory throws this NotSupportedException when the argument expression in a setup cannot be reduced to a supported matcher form. Moq supports constant expressions, member access (property/field), matchers like It.*, quoted expression trees (ExpressionMatcher), and array initializers; anything else falls through to this error.

Solutions

  1. Pre-compute the value into a local variable and pass the constant
  2. Replace the expression with an argument matcher: It.Is<T>(x => ...) or It.IsAny<T>()
  3. For ref/expr arguments, pass a constant or quoted expression Moq can reduce

Example fix

// before
mock.Setup(m => m.Calculate(x + y));
// after
var sum = x + y;
mock.Setup(m => m.Calculate(It.Is<int>(v => v == sum)));
Defensive patterns

Strategy: try-catch

Validate before calling

// before setup, ensure arguments are constants or It matchers
foreach (var arg in args) if (!(arg is ConstantExpression || arg?.NodeType == ExpressionType.MemberAccess)) throw new InvalidOperationException("Unsupported setup argument");

Type guard

static bool IsSupportedSetupArg(Expression e) => e is ConstantExpression || e.NodeType is ExpressionType.MemberAccess or ExpressionType.Quote or ExpressionType.NewArrayInit;

Try / catch

try { mock.Setup(m => m.Method(Compute())); } catch (NotSupportedException ex) when (ex.Message.Contains("Unsupported expression")) { /* hoist to local, use It.Is */ }

Prevention

When it happens

Trigger: Using an unsupported expression as a setup argument, e.g. method calls, arithmetic, lambdas, or other reducible-but-unsupported node types: `mock.Setup(m => m.Method(ComputeValue()))` or `m.Method(a + b)`.

Common situations: Developers embedding computed values or helper-method calls directly in setup expressions instead of matchers or constants.

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


AI-assisted analysis of devlooped/moq@89a5be629c (2026-09-16). Data as JSON: /api/errors/3b07d304d33705af. Report an issue: GitHub.

Appendix: source

Thrown at src/Moq/MatcherFactory.cs:196

                if (expression.IsMatch(out var match))
                {
                    return new Pair<IMatcher, Expression>(match, expression);
                }
            }

            // Try reducing locals to get a constant.
            var reduced = originalExpression.PartialEval();
            if (reduced.NodeType == ExpressionType.Constant)
            {
                return new Pair<IMatcher, Expression>(new ConstantMatcher(((ConstantExpression)reduced).Value), reduced);
            }

            if (reduced.NodeType == ExpressionType.Quote)
            {
                return new Pair<IMatcher, Expression>(new ExpressionMatcher(((UnaryExpression)expression).Operand), reduced);
            }

            throw new NotSupportedException(
                string.Format(CultureInfo.CurrentCulture, Resources.UnsupportedExpression, originalExpression));
        }
    }
}

View on GitHub (pinned to 89a5be629c)