devlooped/moq · error · ArgumentException
Expression is not an event remove
Error message
Expression is not an event remove: {0} What it means
The mirror of the event-add guard: it validates that the lambda passed to mock.SetupRemove is an event remove-accessor expression (x => x.MyEvent -= handler). Anything else (add assignment, method call, property access) causes Moq to throw ArgumentException with the offending expression.
Solutions
- Use a remove-assignment expression: mock.SetupRemove(x => x.MyEvent -= It.IsAny<EventHandler>()).
- Use mock.SetupAdd if you meant the += accessor.
- Ensure the event is overridable/interface-based so Moq can intercept it.
- Check the expression body uses -= on an event member.
Example fix
// before mock.SetupRemove(x => x.MyEvent += handler); // add, not remove // after mock.SetupRemove(x => x.MyEvent -= It.IsAny<EventHandler>());
Defensive patterns
Strategy: validation
Validate before calling
bool isRemoveExpr(Expression e) => e is BinaryExpression b && b.NodeType == ExpressionType.SubtractAssign && b.Left is MemberExpression me && me.Member is EventInfo;
Try / catch
try { mock.SetupRemove(x => x.MyEvent -= It.IsAny<EventHandler>()); }
catch (ArgumentException ex) when (ex.Message.StartsWith("Expression is not an event remove")) { /* fix lambda to use -= on an event */ throw; } Prevention
- SetupRemove requires `-=` on a virtual/interface event.
- Use SetupAdd for `+=`.
- Copy-paste event setup lambdas carefully between add/remove.
When it happens
Trigger: Calling mock.SetupRemove with x => x.Event += handler (add instead of remove), a method call, or any non-remove-accessor expression body.
Common situations: Confusing SetupRemove with SetupAdd; verifying unsubscription logic but passing the subscription lambda by copy-paste; events that are not virtual/interface 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 add
- 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/ac46f68d30d81196.
Report an issue: GitHub.
Appendix: source
Thrown at src/Moq/Guard.cs:157
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;
}
throw new ArgumentException(
string.Format(
CultureInfo.CurrentCulture,
Resources.SetupNotEventRemove,
expression.ToStringFixed()),
paramName);
}
/// <summary>
/// Ensures the given <paramref name="value"/> is not null.
/// Throws <see cref="ArgumentNullException"/> otherwise.
/// </summary>
#if NULLABLE_REFERENCE_TYPES
public static void NotNull([NotNull] object? value, string paramName)
#else
public static void NotNull(object? value, string paramName)
#endif
{
if (value == null)View on GitHub (pinned to 89a5be629c)