{"record":{"id":"36838d503f2fbbef","repo":"devlooped/moq","slug":"notsupportedexception-no-message-duck-member-is-neither-a","errorCode":null,"errorMessage":"NotSupportedException (no message: duck member is neither a method nor a property)","messagePattern":"NotSupportedException \\(no message: duck member is neither a method nor a property\\)","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"src/Moq/Protected/ProtectedAsMock.cs","lineNumber":291,"sourceCode":"                else\n                {\n                    return base.VisitMember(node);\n                }\n            }\n\n            MemberInfo FindCorrespondingMember(MemberInfo duckMember)\n            {\n                if (duckMember is MethodInfo duckMethod)\n                {\n                    return FindCorrespondingMethod(duckMethod);\n                }\n                else if (duckMember is PropertyInfo duckProperty)\n                {\n                    return FindCorrespondingProperty(duckProperty);\n                }\n                else\n                {\n                    throw new NotSupportedException();\n                }\n            }\n\n            MethodInfo FindCorrespondingMethod(MethodInfo duckMethod)\n            {\n                var candidateTargetMethods =\n                    this.targetType\n                    .GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)\n                    .Where(ctm => IsCorrespondingMethod(duckMethod, ctm))\n                    .ToArray();\n\n                if (candidateTargetMethods.Length == 0)\n                {\n                    throw new ArgumentException(string.Format(Resources.ProtectedMemberNotFound, this.targetType, duckMethod));\n                }\n\n                Debug.Assert(candidateTargetMethods.Length == 1);\n","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/devlooped/moq/blob/89a5be629c752960fe403e95ff583e4ae6f00542/src/Moq/Protected/ProtectedAsMock.cs#L273-L309","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before (analog class has a public field)\nmock.Protected().As<Analog>().Verify(a => a.threshold);\n// after\nclass Analog { public int Threshold { get; set; } }\nmock.Protected().As<Analog>().Verify(a => a.Threshold);","handlingStrategy":"type-guard","validationCode":"static bool IsLambdaMemberSupported(System.Linq.Expressions.MemberInfo m) => m is MethodInfo or PropertyInfo;","typeGuard":"static bool IsSupportedMember(System.Linq.Expressions.Expression e) =>\n    e is System.Linq.Expressions.MemberExpression me && (me.Member is MethodInfo or PropertyInfo);","tryCatchPattern":"try { mock.Protected().As<Analog>().Verify(a => a.SomeMember); }\ncatch (NotSupportedException) { /* analog lambda used a field/event: restructure */ }","preventionTips":["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"],"tags":["moq","unsupported-operation","expression-trees","fields"],"backgroundTag":"unsupported-operation","analyzedSha":"89a5be629c752960fe403e95ff583e4ae6f00542","analyzedAt":"2026-09-16T05:31:39.496Z","contentChangedAt":"2026-09-16T05:31:39.496Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}