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
- Use an add-assignment expression: mock.SetupAdd(x => x.MyEvent += It.IsAny<EventHandler>()).
- Use mock.SetupRemove if you meant the -= accessor.
- Ensure the event is virtual/overridable (or interface member) so it can be set up.
- 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
- SetupAdd requires `+=` on a virtual/interface event.
- Use SetupRemove for `-=`.
- Do not substitute method calls for event accessors in setup lambdas.
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
- Expression is not an event remove
- Unsupported expression
- Expression is not a setter
- Resources.UnsupportedExpression (formatted with…
- Unhandled expression type
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)