devlooped/moq · error · ArgumentException
Type does not have matching protected member
Error message
Type {0} does not have matching protected member: {1} What it means
ProtectedAsMock's DuckReplacer maps a protected method called on the analog type to a matching protected method on the mocked type. When no method on T (searched with NonPublic | Instance bindings) satisfies IsCorrespondingMethod, this ArgumentException with Resources.ProtectedMemberNotFound ('Type {0} does not have matching protected member: {1}') is thrown. It surfaces to the caller wrapped with paramName 'expression'.
Solutions
- Confirm the method exists on T as a protected (or protected internal) instance method with an identical name and signature
- Update TAnalog to declare the method exactly as it exists on T (name, parameter types, return type)
- If the method became public, use the strong-typed Mock<T>.Setup/Verify instead of the Protected API
- Verify you are mocking the concrete type that actually declares/overrides the protected member
Example fix
// before (T has Compute(int), analog declares Compute(long))
mock.Protected().As<IAnalog>().Setup(a => a.Compute(2L));
// after
class Analog { ... int Compute(int x); }
mock.Protected().As<IAnalog>().Setup(a => a.Compute(2)); Defensive patterns
Strategy: validation
Validate before calling
static bool HasProtectedMethod(Type target, string name, Type[] paramTypes) =>
target.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
.Any(m => m.Name == name && m.GetParameters().Select(p => p.ParameterType).SequenceEqual(paramTypes)); Try / catch
try { mock.Protected().As<IAnalog>().Setup(a => a.Compute(1)); }
catch (ArgumentException ex) when (ex.Message.Contains("does not have matching protected member")) { /* align analog with T */ } Prevention
- Assert analog/target alignment in a unit test using reflection
- Update TAnalog immediately when the mocked library changes protected signatures
- Use nameof-style references where feasible to catch renames at compile time
- Pin the mocked library version and review its changelog for protected-member changes
When it happens
Trigger: mock.Protected().As<TAnalog>().Setup/Verify(a => a.Method(args)) where the mocked type T lacks a protected instance method with the same name, generic arity, and compatible parameter/return types.
Common situations: Test-double analog interface written by hand diverges from the real class; protected method overloads renamed after a refactor; signature drift after upgrading the mocked library (parameter type changed, added overload); mocking a derived type but the method is protected on the base with different accessibility.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- No protected method . found whose signature is compatible…
- ex.Message (re-thrown ArgumentException with paramName…
- Member . does not exist.
- "public bool ( ) in class .
- ex.Message from ReplaceDuck expression rewriting (rethrown…
AI-assisted analysis of devlooped/moq@89a5be629c (2026-09-16).
Data as JSON: /api/errors/30fdddfeb94f94c8.
Report an issue: GitHub.
Appendix: source
Thrown at src/Moq/Protected/ProtectedAsMock.cs:305
return FindCorrespondingProperty(duckProperty);
}
else
{
throw new NotSupportedException();
}
}
MethodInfo FindCorrespondingMethod(MethodInfo duckMethod)
{
var candidateTargetMethods =
this.targetType
.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
.Where(ctm => IsCorrespondingMethod(duckMethod, ctm))
.ToArray();
if (candidateTargetMethods.Length == 0)
{
throw new ArgumentException(string.Format(Resources.ProtectedMemberNotFound, this.targetType, duckMethod));
}
Debug.Assert(candidateTargetMethods.Length == 1);
var targetMethod = candidateTargetMethods[0];
if (targetMethod.IsGenericMethodDefinition)
{
var duckGenericArgs = duckMethod.GetGenericArguments();
targetMethod = targetMethod.MakeGenericMethod(duckGenericArgs);
}
return targetMethod;
}
PropertyInfo FindCorrespondingProperty(PropertyInfo duckProperty)
{
var candidateTargetProperties =View on GitHub (pinned to 89a5be629c)