devlooped/moq · error · ArgumentException
To specify a setup for public property
Error message
To specify a setup for public property {0}.{1}, use the typed overloads, such as:
mock.Setup(x => x.{1}).Returns(value);
mock.SetupGet(x => x.{1}).Returns(value); //equivalent to previous one
mock.SetupSet(x => x.{1}).Callback(callbackDelegate);
What it means
SetupGet/Setup-family APIs for protected members call ThrowIfPublicGetter to reject properties whose getter is public on the mocked type, throwing ArgumentException with Resources.UnexpectedPublicProperty that lists the typed-overload alternatives (Setup, SetupGet, SetupSet with lambdas). The Protected API must only be used for non-public property getters.
Solutions
- Use the strong-typed mock.Setup(x => x.Prop).Returns(v) or mock.SetupGet(x => x.Prop).Returns(v)
- If only the getter is public but setter is protected, keep using Protected().SetupSet for the setter path
- Update tests after accessibility changes in a library upgrade
Example fix
// before
mock.Protected().Setup<string>("Name");
// after
mock.SetupGet(x => x.Name).Returns("abc"); // Name getter is public Defensive patterns
Strategy: validation
Validate before calling
static bool GetterIsProtected(Type t, string prop) =>
t.GetProperty(prop, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance) is { } p
&& p.GetGetMethod(true) is { } g && !g.IsPublic; Try / catch
try { mock.Protected().Setup<string>("Name"); }
catch (ArgumentException ex) when (ex.Message.Contains("public property")) { /* use mock.SetupGet(x => x.Name) */ } Prevention
- Verify getter accessibility before choosing Protected().Setup/SetupGet
- Re-validate after library upgrades that change accessibility
- Use SetupGet/SetupSet on Mock<T> for public getters
- Document in test helpers which members are protected
When it happens
Trigger: mock.Protected().Setup<string>("PublicProp") or SetupGet("PublicProp") where T.PublicProp has a public getter — common after the property's accessibility changed to public.
Common situations: Property was protected in an older library version and became public; developer assumed non-public; Setup used for a getter-style property that is actually public.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Method . is public. Use strong-typed Expect overload…
- ex.Message from ReplaceDuck expression rewriting (rethrown…
- ex.Message (re-thrown ArgumentException with paramName…
- Type does not have matching protected member
- Member . does not exist.
AI-assisted analysis of devlooped/moq@89a5be629c (2026-09-16).
Data as JSON: /api/errors/6c23ae7b6015eb18.
Report an issue: GitHub.
Appendix: source
Thrown at src/Moq/Protected/ProtectedMock.cs:427
}
static void ThrowIfPublicMethod(MethodInfo method, string reflectedTypeName)
{
if (method.IsPublic)
{
throw new ArgumentException(string.Format(
CultureInfo.CurrentCulture,
Resources.MethodIsPublic,
reflectedTypeName,
method.Name));
}
}
static void ThrowIfPublicGetter(PropertyInfo property, string reflectedTypeName)
{
if (property.CanRead(out var getter) && getter.IsPublic)
{
throw new ArgumentException(string.Format(
CultureInfo.CurrentCulture,
Resources.UnexpectedPublicProperty,
reflectedTypeName,
property.Name));
}
}
static void ThrowIfPublicSetter(PropertyInfo property, string reflectedTypeName)
{
if (property.CanWrite(out var setter) && setter.IsPublic)
{
throw new ArgumentException(string.Format(
CultureInfo.CurrentCulture,
Resources.UnexpectedPublicProperty,
reflectedTypeName,
property.Name));
}
}View on GitHub (pinned to 89a5be629c)