devlooped/moq · error · ArgumentException

Expression is not a setter

Error message

Expression is not a setter: {0}

What it means

This guard validates that a lambda expression passed to a setup API is an assignment to a property or indexer (a setter), e.g. mock.SetupSet(x => x.Prop = value). If the expression body is not an assignment whose target is a property/indexer (or a Call that is a set accessor), Moq throws ArgumentException. It ensures SetupSet/SetupOnlySet receive valid setter expressions.

Solutions

  1. Use an assignment expression in SetupSet: mock.SetupSet(x => x.Prop = It.IsAny<string>()).
  2. Use mock.Setup(x => x.Prop) instead if you meant a getter setup.
  3. If assigning a field, convert the field to a property (or mock the interface) since fields cannot be mocked.
  4. Verify you are calling SetupSet/SetupOnlySet, not Setup.

Example fix

// before
mock.SetupSet(x => x.Name); // getter, not a setter
// after
mock.SetupSet(x => x.Name = It.IsAny<string>());
Defensive patterns

Strategy: validation

Validate before calling

bool isSetterLambda(Expression<Func<T,object>> e) => e.Body is BinaryExpression b && b.NodeType == ExpressionType.Assign && (b.Left is MemberExpression || b.Left is IndexExpression);

Type guard

static bool IsSetterExpr<T>(Expression<Func<T, object>> e) => e.Body is BinaryExpression { NodeType: ExpressionType.Assign, Left: MemberExpression or IndexExpression };

Try / catch

try { mock.SetupSet(x => x.Name = It.IsAny<string>()); }
catch (ArgumentException ex) when (ex.Message.StartsWith("Expression is not a setter")) { /* use Setup for getters instead */ throw; }

Prevention

When it happens

Trigger: Calling mock.SetupSet with a getter expression (x => x.Prop), a method call that is not a set accessor, a field assignment, or a compound/unsupported body.

Common situations: Confusing Setup with SetupSet (passing a getter where a setter is required); assigning to a public field instead of a property; setting up read-only or expression-bodied properties.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at src/Moq/Guard.cs:76

        public static void IsAssignmentToPropertyOrIndexer(LambdaExpression expression, string paramName)
        {
            Debug.Assert(expression != null);

            switch (expression.Body.NodeType)
            {
                case ExpressionType.Assign:
                    var assignment = (BinaryExpression)expression.Body;
                    if (assignment.Left is MemberExpression || assignment.Left is IndexExpression) return;
                    break;

                case ExpressionType.Call:
                    var call = (MethodCallExpression)expression.Body;
                    if (call.Method.IsSetAccessor()) return;
                    break;
            }

            throw new ArgumentException(
                string.Format(
                    CultureInfo.CurrentCulture,
                    Resources.SetupNotSetter,
                    expression.ToStringFixed()),
                paramName);
        }

        public static void IsOverridable(MethodInfo method, Expression expression)
        {
            if (method.IsStatic)
            {
                throw new NotSupportedException(
                    string.Format(
                        CultureInfo.CurrentCulture,
                        Resources.UnsupportedExpressionWithHint,
                        expression.ToStringFixed(),
                        string.Format(
                            CultureInfo.CurrentCulture,

View on GitHub (pinned to 89a5be629c)