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

  1. Confirm the method exists on T as a protected (or protected internal) instance method with an identical name and signature
  2. Update TAnalog to declare the method exactly as it exists on T (name, parameter types, return type)
  3. If the method became public, use the strong-typed Mock<T>.Setup/Verify instead of the Protected API
  4. 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

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


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)