devlooped/moq · error · ArgumentException
Property . does not have a setter.
Error message
Property {0}.{1} does not have a setter. What it means
Moq throws this ArgumentException when setting up or reading a property that has no setter (read-only/getter-only property). Operations that require writing through the property, such as SetupProperty or SetupSet/VerifySet, fail because the property cannot be assigned.
Solutions
- Use mock.Setup(m => m.Prop).Returns(value) to stub the getter instead of writing the property.
- For SetupProperty-style tracking, keep an auto-property with a setter or track via a callback.
- If the property must be assignable in tests, add an internal/public setter (or constructor/setter injection) on the type.
- Verify get behavior with VerifyGet rather than VerifySet for read-only properties.
Example fix
// before mock.SetupProperty(m => m.Count); // Count is read-only // after mock.Setup(m => m.Count).Returns(5);
Defensive patterns
Strategy: type-guard
Validate before calling
static bool HasSetter(Type t, string name) =>
t.GetProperty(name)?.GetSetMethod(nonPublic: false) != null;
Type guard
static bool IsWritable(System.Reflection.PropertyInfo p) => p.CanWrite;
Try / catch
try { mock.SetupProperty(expr); }
catch (ArgumentException ex) when (ex.Message.Contains("does not have a setter"))
{
// use Setup(...).Returns(...) instead of property-write setups
}
Prevention
- Check PropertyInfo.CanWrite before SetupProperty/SetupSet/VerifySet
- Stub read-only properties with Setup(m => m.P).Returns(...)
- Keep mutable state behind interfaces with settable properties when tests must write
- Avoid SetupProperty on expression-bodied/getter-only properties
When it happens
Trigger: mock.SetupProperty(m => m.ReadOnlyProp); mock.SetupSet(m => m.ReadOnlyProp = ...); VerifySet on a getter-only property; DefaultValue.Mock with loose tracking on read-only property.
Common situations: Mocking immutable-style types exposing getter-only properties; trying to stub a computed/expression-bodied property; after a setter was removed during refactoring to immutability.
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
- Property . does not have a getter.
- Unsupported expression
- Expression is not a setter
- Resources.ArgumentMatcherWillNeverMatch (formatted with…
- Resources.UnsupportedExpression (formatted with…
AI-assisted analysis of devlooped/moq@89a5be629c (2026-09-16).
Data as JSON: /api/errors/1939f3da25dc4b32.
Report an issue: GitHub.
Appendix: source
Thrown at src/Moq/Guard.cs:242
}
}
public static void CanRead(PropertyInfo property)
{
if (!property.CanRead(out _))
{
throw new ArgumentException(string.Format(
CultureInfo.CurrentCulture,
Resources.PropertyGetNotFound,
property.DeclaringType!.Name, property.Name));
}
}
public static void CanWrite(PropertyInfo property)
{
if (!property.CanWrite(out _))
{
throw new ArgumentException(string.Format(
CultureInfo.CurrentCulture,
Resources.PropertySetNotFound,
property.DeclaringType!.Name, property.Name));
}
}
}
}
View on GitHub (pinned to 89a5be629c)