devlooped/moq · error · Exception

Unhandled expression type

Error message

Unhandled expression type: {0}

What it means

Moq's expression-to-string formatter (used to render lambda expressions like `x => x.Foo()` in verification messages) walks the expression tree with a switch over node types. When it encounters an expression node type it has no case for, it throws this generic Exception with the unhandled NodeType in the message. It is an internal completeness guard, meaning Moq's AppendExpression does not support that expression construct.

Solutions

  1. Identify the NodeType printed in the message and simplify the expression to constructs Moq supports (member access, method calls, simple binary/conditional expressions)
  2. Extract the unsupported construct into a plain helper method called from the expression where possible, or compute values outside the lambda and use a variable
  3. Verify with a different overload, e.g. capture the expression differently or use It.Is<T> predicates inside supported calls
  4. If the node type is a common one, file/patch an issue in Moq's StringBuilderExtensions.AppendExpression switch

Example fix

// before
mock.Verify(m => m.Foo(x => x switch { 1 => "a", _ => "b" }));
// after
string Pick(int x) => x switch { 1 => "a", _ => "b" };
mock.Verify(m => m.Foo(x => Pick(x)));
Defensive patterns

Strategy: validation

Validate before calling

// keep setup/verify lambdas to member access, method calls and simple operators
Expression<Func<T, TResult>> expr = x => x.Foo(1); // supported
// avoid: switch expressions, ??=, dynamic, pattern constructs inside the lambda

Prevention

When it happens

Trigger: Passing a lambda to Mock.Of/Verify/Setup whose body uses an expression node type Moq cannot stringify — e.g. switch expressions, coalesce assignment, dynamic operations, index initializers in unusual positions, or newer C# expression forms added after the formatter was written.

Common situations: Using newer C# language features (C# 8/9+ syntax) inside setup/verify expressions; complex nested member-init or list-init expressions; upgrading the compiler/framework so previously unsupported nodes appear.

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

Appendix: source

Thrown at src/Moq/StringBuilderExtensions.AppendExpression.cs:122

                case ExpressionType.Invoke:
                    return builder.AppendExpression((InvocationExpression)expression);

                case ExpressionType.MemberInit:
                    return builder.AppendExpression((MemberInitExpression)expression);

                case ExpressionType.ListInit:
                    return builder.AppendExpression((ListInitExpression)expression);

                case ExpressionType.Extension:
                    if (expression is MatchExpression me)
                    {
                        return builder.AppendExpression(me);
                    }
                    goto default;

                default:
                    throw new Exception(string.Format(Resources.UnhandledExpressionType, expression.NodeType));
            }
        }

        static StringBuilder AppendElementInit(this StringBuilder builder, ElementInit initializer)
        {
            return builder.AppendCommaSeparated("{ ", initializer.Arguments, AppendExpression, " }");
        }

        static StringBuilder AppendExpression(this StringBuilder builder, UnaryExpression expression)
        {
            switch (expression.NodeType)
            {
                case ExpressionType.Convert:
                case ExpressionType.ConvertChecked:
                    return builder.Append('(')
                                  .AppendNameOf(expression.Type)
                                  .Append(')')
                                  .AppendExpression(expression.Operand);

View on GitHub (pinned to 89a5be629c)