devlooped/moq · error · ArgumentException

Expression is not an event add

Error message

Expression is not an event add: {0}

What it means

This guard validates that the lambda passed to an event setup API (e.g. mock.SetupAdd) is an event add-accessor expression (x => x.MyEvent += handler). If the body is not an add assignment or a call to an add accessor, Moq throws ArgumentException. It ensures event-add setups receive only valid expressions.

Solutions

  1. Use an add-assignment expression: mock.SetupAdd(x => x.MyEvent += It.IsAny<EventHandler>()).
  2. Use mock.SetupRemove if you meant the -= accessor.
  3. Ensure the event is virtual/overridable (or interface member) so it can be set up.
  4. Verify the expression targets an event, not a method or property.

Example fix

// before
mock.SetupAdd(x => x.MyEvent -= handler); // remove, not add
// after
mock.SetupAdd(x => x.MyEvent += It.IsAny<EventHandler>());
Defensive patterns

Strategy: validation

Validate before calling

bool isAddExpr(Expression e) => e is BinaryExpression b && b.NodeType == ExpressionType.AddAssign && b.Left is MemberExpression me && me.Member is EventInfo;

Try / catch

try { mock.SetupAdd(x => x.MyEvent += It.IsAny<EventHandler>()); }
catch (ArgumentException ex) when (ex.Message.StartsWith("Expression is not an event add")) { /* fix lambda to use += on an event */ throw; }

Prevention

When it happens

Trigger: Calling mock.SetupAdd with the wrong expression form: a plain method call, a property, x => x.Event -= handler (remove instead of add), or a field-like event misuse.

Common situations: Swapping SetupAdd and SetupRemove accidentally; using SetupAdd for plain methods; writing the subscription lambda without the += operator; subscribing to events on non-virtual or non-mockable members.

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/7eaa93ef8d8dd409. Report an issue: GitHub.

Appendix: source

Thrown at src/Moq/Guard.cs:137

                    method.DeclaringType!.Name,
                    method.Name,
                    messageIfNotVisible));
            }
        }

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

            switch (expression.Body.NodeType)
            {
                case ExpressionType.Call:
                    var call = (MethodCallExpression)expression.Body;
                    if (call.Method.IsEventAddAccessor()) return;
                    break;
            }

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

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

            switch (expression.Body.NodeType)
            {
                case ExpressionType.Call:
                    var call = (MethodCallExpression)expression.Body;
                    if (call.Method.IsEventRemoveAccessor()) return;
                    break;
            }

View on GitHub (pinned to 89a5be629c)