devlooped/moq · error · ArgumentException

Resources.AsMustBeInterface

Error message

Resources.AsMustBeInterface

What it means

Moq throws this ArgumentException when Mock<T>.As<TInterface>() is called with a TInterface that is not an interface. As<T>() exists to add additional interface implementations to a mock, so only interface type arguments are legal.

Solutions

  1. Only pass interface types to As<TInterface>.
  2. To cast the mock itself, use (Mock<TDerived>)mock or As<TDerived> only when TDerived is an interface the type can implement.
  3. Add a 'where TInterface : class' + runtime IsInterface check in generic wrappers before calling As.

Example fix

// before
var m = mock.As<MyBaseClass>();
// after
var m = mock.As<IDerivedInterface>();
Defensive patterns

Strategy: type-guard

Validate before calling

if (!typeof(TInterface).IsInterface)
    throw new ArgumentException("As<TInterface> requires an interface type.");

Type guard

bool IsInterfaceArg<TInterface>() => typeof(TInterface).IsInterface;

Try / catch

try { return mock.As<TInterface>(); } catch (ArgumentException ex) when (ex.Message.Contains("interface")) { throw new InvalidOperationException("Pass an interface type to As<T>."); }

Prevention

When it happens

Trigger: mock.As<SomeClass>() or mock.As<SomeStruct>() — any call to As<TInterface> where typeof(TInterface).IsInterface is false (src/Moq/Mock`1.cs:384).

Common situations: Using As<T>() to cast to a base class (mistakenly thinking it performs a cast); generic code with an unconstrained T passed to As<T>.

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

Appendix: source

Thrown at src/Moq/Mock`1.cs:384

        ///   The following example creates a mock for the main interface
        ///   and later adds <see cref="IDisposable"/> to it to verify it's called by the consumer code:
        ///   <code>
        ///     var mock = new Mock&lt;IProcessor&gt;();
        ///     mock.Setup(x =&gt; x.Execute("ping"));
        ///
        ///     // add IDisposable interface
        ///     var disposable = mock.As&lt;IDisposable&gt;();
        ///     disposable.Setup(d => d.Dispose())
        ///               .Verifiable();
        ///   </code>
        /// </example>
        public override Mock<TInterface> As<TInterface>()
        {
            var interfaceType = typeof(TInterface);

            if (!interfaceType.IsInterface)
            {
                throw new ArgumentException(Resources.AsMustBeInterface);
            }

            if (typeof(TInterface) == typeof(T))
            {
                return (Mock<TInterface>)(Mock)this;
            }

            if (this.IsObjectInitialized && this.ImplementsInterface(interfaceType) == false)
            {
                throw new InvalidOperationException(Resources.AlreadyInitialized);
            }

            if (this.AdditionalInterfaces.Contains(interfaceType) == false)
            {
                // We get here for either of two reasons:
                //
                // 1. We are being asked to implement an interface that the mocked type does *not* itself
                //    inherit or implement. We need to hand this interface type to DynamicProxy's

View on GitHub (pinned to 89a5be629c)