devlooped/moq · error · NotSupportedException

Expression involves a field access, which is not supported…

Error message

Expression {0} involves a field access, which is not supported. Use properties instead.

What it means

Moq throws this NotSupportedException when a LINQ expression used in a setup (e.g. mock.Setup(...)) contains a field access instead of a property access. Moq matches setups via member expressions and only supports properties, methods, and indexers; CLR fields cannot be intercepted by the generated proxy.

Solutions

  1. Replace the public field with a property on the mocked type (public int X => field; or an auto-property).
  2. If you cannot change the type, set the field directly on the mock's real backing object (use Mock.Of / manual instantiation) instead of Setup, or wrap it behind an interface with properties.
  3. Use SetupSet/VerifySet only on properties; for field state checks, assert on the field value after invoking the code under test rather than setting it up via Moq.

Example fix

// before
mock.Setup(m => m.Name).Returns("x"); // Name is a public FIELD
// after
mock.Setup(m => m.Name).Returns("x"); // after converting Name to a property
// or if the class cannot change:
var real = new Customer { Name = "x" }; // set field directly, don't Setup it
Defensive patterns

Strategy: validation

Validate before calling

static bool IsFieldAccess(LambdaExpression expr)
{
    var body = expr.Body as MemberExpression;
    return body?.Member is System.Reflection.FieldInfo;
}
// before mock.Setup: if (IsFieldAccess(expr)) throw/fix

Type guard

static bool IsProperty(LambdaExpression expr) =>
    (expr.Body as System.Linq.Expressions.MemberExpression)?.Member is System.Reflection.PropertyInfo;

Try / catch

try { mock.Setup(expr).Returns(value); }
catch (NotSupportedException ex) when (ex.Message.Contains("field access"))
{
    // convert the member to a property or set the field directly
}

Prevention

When it happens

Trigger: Calling mock.Setup(m => m.someField) or mock.Verify(m => m.someField) where someField is a public (or accessible) field on the mocked class; also passing a lambda body like m => m.field + 1 that reads a field inside a setup expression.

Common situations: Mocking legacy or DTO classes that expose public fields instead of properties; refactoring a property to a field; third-party/interop types with public fields; copy-pasting member names and accidentally picking a field.

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/0f117bbf025f9ed7. Report an issue: GitHub.

Appendix: source

Thrown at src/Moq/Guard.cs:202

        /// <see cref="ArgumentException"/> in the latter.
        /// </summary>
        public static void NotNullOrEmpty(string value, string paramName)
        {
            if (value == null)
            {
                throw new ArgumentNullException(paramName);
            }

            if (value.Length == 0)
            {
                throw new ArgumentException(Resources.ArgumentCannotBeEmpty, paramName);
            }
        }

        public static void NotField(MemberExpression memberAccess)
        {
            if (memberAccess.Member is FieldInfo)
                throw new NotSupportedException(
                    string.Format(
                        Resources.FieldsNotSupported,
                        memberAccess.ToStringFixed()));
        }

        public static void IsMockable(Type type)
        {
            if (!type.IsMockable())
            {
                throw new NotSupportedException(
                    string.Format(
                        Resources.TypeNotMockable,
                        type.GetFormattedName()));
            }
        }

        public static void Positive(TimeSpan delay)
        {

View on GitHub (pinned to 89a5be629c)