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

  1. Make the intermediate member's return type an interface or non-sealed class so Moq can mock it
  2. 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
  3. Use Mock.Of<T>() / loose chains only over mockable types
  4. 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

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


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)