{"record":{"id":"18d6b62da5561d62","repo":"devlooped/moq","slug":"ex-message-re-thrown-argumentexception-with-paramname","errorCode":null,"errorMessage":"ex.Message (re-thrown ArgumentException with paramName 'expression')","messagePattern":"ex\\.Message \\(re-thrown ArgumentException with paramName 'expression'\\)","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Moq/Protected/ProtectedAsMock.cs","lineNumber":209,"sourceCode":"        {\n            Guard.NotNull(setterExpression, nameof(setterExpression));\n\n            var rewrittenExpression = ReconstructAndReplaceSetter(setterExpression);\n            Mock.VerifySet(mock, rewrittenExpression, times.HasValue ? times.Value : Times.AtLeastOnce(), failMessage);\n        }\n\n        public void VerifyGet<TProperty>(Expression<Func<TAnalog, TProperty>> expression, Times? times = null, string? failMessage = null)\n        {\n            Guard.NotNull(expression, nameof(expression));\n\n            Expression<Func<T, TProperty>> rewrittenExpression;\n            try\n            {\n                rewrittenExpression = (Expression<Func<T, TProperty>>)ReplaceDuck(expression);\n            }\n            catch (ArgumentException ex)\n            {\n                throw new ArgumentException(ex.Message, nameof(expression));\n            }\n\n            Mock.VerifyGet(this.mock, rewrittenExpression, times ?? Times.AtLeastOnce(), failMessage);\n        }\n\n        LambdaExpression ReconstructAndReplaceSetter(Action<TAnalog> setterExpression)\n        {\n            var expression = ExpressionReconstructor.Instance.ReconstructExpression(setterExpression, mock.ConstructorArguments);\n            return ReplaceDuck(expression);\n        }\n\n        static LambdaExpression ReplaceDuck(LambdaExpression expression)\n        {\n            Debug.Assert(expression.Parameters.Count == 1);\n\n            var targetParameter = Expression.Parameter(typeof(T), expression.Parameters[0].Name);\n            return Expression.Lambda(DuckReplacerInstance.Visit(expression.Body), targetParameter);\n        }","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/devlooped/moq/blob/89a5be629c752960fe403e95ff583e4ae6f00542/src/Moq/Protected/ProtectedAsMock.cs#L191-L227","documentation":"Same rethrow pattern as Verify: ProtectedAsMock.VerifyGet rewrites the lambda from TAnalog to the mocked type T, and any ArgumentException during that rewriting (typically a missing matching protected property) is rethrown with paramName 'expression'. The message describes which protected member could not be matched.","triggerScenarios":"Calling mock.Protected().As<TAnalog>().VerifyGet(x => x.SomeProperty, ...) where TAnalog's property has no corresponding protected property on T.","commonSituations":"Analog type declares a property that is a field or method on T, property renamed/made public on T, or the analog interface was hand-written against an older version of the mocked class.","solutions":["Add or fix the corresponding protected property on the mocked type T so the duck-typing rewrite can match it","Align TAnalog's property declaration with the actual protected property name/type on T","Use Protected().SetupGet/VerifyGet with the exact string member name on the non-As API if the member is hard to express in the analog","Use the strong-typed VerifyGet on Mock<T> if the property is public"],"exampleFix":"// before (analog property name does not exist as protected on T)\nmock.Protected().As<IAnalog>().VerifyGet(a => a.Value);\n// after\n// class T { protected virtual string Value { get {...} } }\nmock.Protected().As<IAnalog>().VerifyGet(a => a.Value);","handlingStrategy":"validation","validationCode":"static bool HasMatchingProtectedProperty(Type target, string name) =>\n    target.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).Any(p => p.Name == name);","typeGuard":null,"tryCatchPattern":"try { mock.Protected().As<IAnalog>().VerifyGet(a => a.Value); }\ncatch (ArgumentException ex) when (ex.ParamName == \"expression\") { /* fix analog/target property mismatch */ }","preventionTips":["Keep TAnalog minimal (only members actually verified)","Mirror exact property names and types from T","Add a test that visits all TAnalog properties and checks existence on T","Prefer SetupGet/VerifyGet with string names on Protected() when possible"],"tags":["moq","reflection","expression-rewriting","protected-members"],"backgroundTag":"invalid-argument-value","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"}