devlooped/moq · error · NotSupportedException
NotSupportedException (no message: duck member is neither a…
Error message
NotSupportedException (no message: duck member is neither a method nor a property)
What it means
During duck-expression rewriting, DuckReplacer.FindCorrespondingMember only knows how to map MethodInfo and PropertyInfo members accessed on the analog parameter. If the lambda accesses any other member kind (e.g. a field, event, or nested type), a bare NotSupportedException with no message is thrown. This is a limitation guard of the analog-rewriting visitor.
Solutions
- Replace the field/event access in the analog with a property or method
- Restructure TAnalog as an interface exposing only methods and properties
- Access constant/field values outside the lambda (capture in a local) instead of through the analog parameter
Example fix
// before (analog class has a public field)
mock.Protected().As<Analog>().Verify(a => a.threshold);
// after
class Analog { public int Threshold { get; set; } }
mock.Protected().As<Analog>().Verify(a => a.Threshold); Defensive patterns
Strategy: type-guard
Validate before calling
static bool IsLambdaMemberSupported(System.Linq.Expressions.MemberInfo m) => m is MethodInfo or PropertyInfo;
Type guard
static bool IsSupportedMember(System.Linq.Expressions.Expression e) =>
e is System.Linq.Expressions.MemberExpression me && (me.Member is MethodInfo or PropertyInfo); Try / catch
try { mock.Protected().As<Analog>().Verify(a => a.SomeMember); }
catch (NotSupportedException) { /* analog lambda used a field/event: restructure */ } Prevention
- Define TAnalog as an interface with only methods and properties
- Never access fields, events, or nested types through the analog parameter in lambdas
- Expose constant values as properties in the analog type
When it happens
Trigger: mock.Protected().As<TAnalog>() lambdas that access a field (x => x.someField), an event, or any non-method/non-property member of TAnalog — reached via VisitMember during Setup/Verify/VerifyGet rewriting.
Common situations: Analog type is a class (not interface) exposing public fields; accessing constants/fields from the analog class; accidentally referencing a nested type in the lambda.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Expression involves a field access, which is not supported…
- Resources.CallBaseCannotBeUsedWithDelegateMocks
- Resources.CallBaseCannotBeUsedWithDelegateMocks
- Unsupported expression
- Could not determine the correct positions for all argument…
AI-assisted analysis of devlooped/moq@89a5be629c (2026-09-16).
Data as JSON: /api/errors/36838d503f2fbbef.
Report an issue: GitHub.
Appendix: source
Thrown at src/Moq/Protected/ProtectedAsMock.cs:291
else
{
return base.VisitMember(node);
}
}
MemberInfo FindCorrespondingMember(MemberInfo duckMember)
{
if (duckMember is MethodInfo duckMethod)
{
return FindCorrespondingMethod(duckMethod);
}
else if (duckMember is PropertyInfo duckProperty)
{
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);
View on GitHub (pinned to 89a5be629c)