devlooped/moq · error · ArgumentException

Can't set return value for void method

Error message

Can't set return value for void method {0}.

What it means

Moq's Protected() API throws this ArgumentException when you attempt to set up a return value for a method that has a void return type. Void methods have nothing to return, so a Returns/ReturnsAsync setup is meaningless and the library rejects it eagerly at setup time.

Solutions

  1. Remove the Returns(...) call; for void protected methods use Protected().Setup(...) with callbacks only (e.g. .Callback(...)) or just mock.Setup(...) raising events
  2. If a value is needed, change the protected method signature to return a value, or verify the void call instead with Protected().Verify(...)

Example fix

// before
mock.Protected().Setup("OnChanged").Returns(true); // OnChanged is void
// after
mock.Protected().Setup("OnChanged").Callback(() => changed = true);
Defensive patterns

Strategy: validation

Validate before calling

if (methodInfo.ReturnType == typeof(void)) throw new InvalidOperationException("Do not call Returns on a void method: " + methodInfo.Name);

Try / catch

try { mock.Protected().Setup("OnChanged").Returns(true); } catch (ArgumentException ex) { /* drop the Returns or use Callback */ }

Prevention

When it happens

Trigger: Calling Protected().Setup(...) with a Returns(...) (or SetupSequence with returns) on a protected method whose MethodInfo.ReturnType is typeof(void), e.g. a protected void OnSomething() method.

Common situations: Copy-pasting a setup from a non-void method onto a protected event-raiser or callback-style void method; expecting Setup to also register a callback for void members.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of devlooped/moq@89a5be629c (2026-09-16). Data as JSON: /api/errors/abd26af0d248b6ee. Report an issue: GitHub.

Appendix: source

Thrown at src/Moq/Protected/ProtectedMock.cs:451

        }

        static void ThrowIfPublicSetter(PropertyInfo property, string reflectedTypeName)
        {
            if (property.CanWrite(out var setter) && setter.IsPublic)
            {
                throw new ArgumentException(string.Format(
                    CultureInfo.CurrentCulture,
                    Resources.UnexpectedPublicProperty,
                    reflectedTypeName,
                    property.Name));
            }
        }

        static void ThrowIfVoidMethod(MethodInfo method)
        {
            if (method.ReturnType == typeof(void))
            {
                throw new ArgumentException(Resources.CantSetReturnValueForVoid);
            }
        }

        static Type?[] ToArgTypes(object[] args)
        {
            if (args == null)
            {
                throw new ArgumentException(Resources.UseItExprIsNullRatherThanNullArgumentValue);
            }

            var types = new Type?[args.Length];
            for (int index = 0; index < args.Length; index++)
            {
                if (args[index] == null)
                {
                    throw new ArgumentException(Resources.UseItExprIsNullRatherThanNullArgumentValue);
                }

View on GitHub (pinned to 89a5be629c)