devlooped/moq · error · ArgumentException

Resources.ArgumentMatcherWillNeverMatch (formatted with…

Error message

Resources.ArgumentMatcherWillNeverMatch (formatted with matcher expression, operand type, parameter type)

What it means

Moq throws this ArgumentException during matcher creation when the matcher's matched-value type cannot be assigned to the mocked method's parameter type — i.e. the argument matcher will never match. It compares the operand type of a Convert expression against the parameter's type using IsAssignableFrom.

Solutions

  1. Change the matcher's generic type so it matches the method parameter type exactly
  2. Verify the overload being mocked and its parameter types
  3. If a conversion is intended, explicitly convert the matched value (e.g. It.Is<int>(...) on an object parameter won't work — match the declared type)

Example fix

// before
mock.Setup(m => m.Save(It.Is<int>(id => id > 0))); // Save takes string
// after
mock.Setup(m => m.Save(It.Is<string>(s => int.Parse(s) > 0)));
Defensive patterns

Strategy: validation

Validate before calling

var paramType = typeof(IFoo).GetMethod(nameof(IFoo.Save))!.GetParameters()[0].ParameterType;
if (!paramType.IsAssignableFrom(typeof(int))) throw new InvalidOperationException("Matcher type must be assignable to parameter type");

Type guard

static bool MatcherMatchesParam<TParam>(Expression<Func<TParam, bool>> _) => typeof(TParam) == typeof(TParam); // align T with the method's declared parameter type

Try / catch

try { mock.Setup(m => m.Save(It.Is<int>(x => x > 0))); } catch (ArgumentException ex) when (ex.Message.Contains("never match")) { /* fix matcher generic type */ }

Prevention

When it happens

Trigger: Setting up a call with an argument matcher (It.Is<T>, It.IsAny<T>) whose T differs incompatibly from the parameter type, e.g. `mock.Setup(m => m.Method(It.Is<int>(x => x > 5)))` on a method taking a string, or a conversion the parameter type cannot accept.

Common situations: Type mismatches after method signature changes/refactoring; using the wrong generic type argument to It.Is; overload resolution picking a different parameter type than expected.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at src/Moq/MatcherFactory.cs:115

                {
                    if (convertExpression.Operand.IsMatch(out var match))
                    {
                        Type matchedValuesType;

                        if (match.GetType().IsGenericType)
                        {
                            // If match type is `Match<int>`, matchedValuesType set to `int`
                            // Fix for https://github.com/moq/moq4/issues/1199
                            matchedValuesType = match.GetType().GenericTypeArguments[0];
                        }
                        else
                        {
                            matchedValuesType = convertExpression.Operand.Type;
                        }

                        if (!matchedValuesType.IsAssignableFrom(parameter.ParameterType))
                        {
                            throw new ArgumentException(
                                string.Format(
                                    Resources.ArgumentMatcherWillNeverMatch,
                                    convertExpression.Operand.ToStringFixed(),
                                    convertExpression.Operand.Type.GetFormattedName(),
                                    parameter.ParameterType.GetFormattedName()));
                        }
                    }
                }
            }

            return MatcherFactory.CreateMatcher(argument);
        }

        public static Pair<IMatcher, Expression> CreateMatcher(Expression expression)
        {
            // Type inference on the call might 
            // do automatic conversion to the desired 
            // method argument type, and a Convert expression type 

View on GitHub (pinned to 89a5be629c)