devlooped/moq · error · ArgumentException
Resources.UnsupportedExpression + expr.ToStringFixed() + "…
Error message
Resources.UnsupportedExpression + expr.ToStringFixed() + " in " + originalExpression + ":\n" + Resources.TypeNotMockable
What it means
Moq throws this when a setup expression such as mock.Setup(x => x.SomeProperty.SomeMethod()) requires a nested (recursive) mock, but Moq cannot create one because the member's return type is not mockable (sealed/non-interface type without a accessible mock factory). It wraps the unsupported sub-expression and the full expression into an ArgumentException.
Solutions
- Make the intermediate member's return type an interface or non-sealed class so Moq can mock it
- Set up the full chain explicitly with separate stubs (e.g. return a manually created mock of the intermediate object) instead of relying on recursive mocks
- Use Mock.Of<T>() / loose chains only over mockable types
- Restructure the code under test so the deep chain is injected rather than navigated
Example fix
// before
mock.Setup(x => x.Session.User.Name).Returns("bob"); // Session returns sealed type -> throws
// after
var sessionMock = new Mock<ISession>();
sessionMock.Setup(s => s.User.Name).Returns("bob");
mock.Setup(x => x.Session).Returns(sessionMock.Object); Defensive patterns
Strategy: type-guard
Validate before calling
static bool IsMockableChain(Type t) => t.IsInterface || (!t.IsSealed && !t.IsValueType); // verify every intermediate member's return type in the setup chain is mockable before calling Setup
Type guard
static bool CanRecursiveMock(System.Linq.Expressions.Expression e) =>
e is System.Linq.Expressions.MemberExpression me &&
(me.Type.IsInterface || (!me.Type.IsSealed && !me.Type.IsValueType)); Try / catch
try
{
mock.Setup(x => x.A.B.C).Returns(value);
}
catch (ArgumentException ex) when (ex.Message.Contains("TypeNotMockable"))
{
// fall back to explicit stubbing of the chain
} Prevention
- Design chained members to return interfaces
- Avoid setups that navigate through sealed or struct types
- Prefer injecting intermediate objects over deep navigation
- Enable recursive mocking only over known-mockable return types
When it happens
Trigger: mock.Setup(x => x.A.B.C) where an intermediate member's return type is sealed, static, a value type without mock support, or otherwise not mockable by Moq, so GetDefaultValue with DefaultValueProvider.Mock fails to yield an inner mock.
Common situations: Chained property navigation in setups against classes with sealed getters or non-mockable return types; trying to mock third-party sealed types; forgetting to make a nested property return an interface.
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
- The return type of the last member shown above is not…
- Unsupported expression
- Ref expression must evaluate to a constant value.
- Resources.UnsupportedExpression (formatted with…
- Resources.UnsupportedExpression (formatted with expression)
AI-assisted analysis of devlooped/moq@89a5be629c (2026-09-16).
Data as JSON: /api/errors/bcec64ec3ee51d07.
Report an issue: GitHub.
Appendix: source
Thrown at src/Moq/Mock.cs:667
static TSetup SetupRecursive<TSetup>(Mock mock, LambdaExpression originalExpression, Stack<MethodExpectation> parts, Func<Mock, Expression, MethodExpectation, TSetup> setupLast)
where TSetup : ISetup?
{
var part = parts.Pop();
var (expr, method, arguments) = part;
if (parts.Count == 0)
{
return setupLast(mock, originalExpression, part);
}
else
{
Mock? innerMock = mock.MutableSetups.FindLastInnerMock(setup => setup.Matches(part));
if (innerMock == null)
{
var returnValue = mock.GetDefaultValue(method, out innerMock, useAlternateProvider: DefaultValueProvider.Mock);
if (innerMock == null)
{
throw new ArgumentException(
string.Format(
CultureInfo.CurrentCulture,
Resources.UnsupportedExpression,
expr.ToStringFixed() + " in " + originalExpression.ToStringFixed() + ":\n" + Resources.TypeNotMockable));
}
var innerMockSetup = new InnerMockSetup(originalExpression, mock, expectation: part, returnValue);
mock.MutableSetups.Add(innerMockSetup);
}
Debug.Assert(innerMock != null);
return Mock.SetupRecursive(innerMock, originalExpression, parts, setupLast);
}
}
internal static void SetupAllProperties(Mock mock)
{
mock.MutableSetups.Add(new StubbedPropertiesSetup(mock));
}View on GitHub (pinned to 89a5be629c)