devlooped/moq · error · ArgumentNullException

callback (Argument is null)

Error message

callback (Argument is null)

What it means

SetCallbackBehavior installs the delegate that runs when the mocked member is invoked; Moq requires a non-null callback because a setup whose callback is null would leave the call pipeline with no user behavior to execute and fail later at invocation time. The throw site is a standard ArgumentNullException guard: the faulty input is a null Delegate argument, e.g. mock.Setup(...).Callback(null) or a conditionally-built delegate that turned out to be null.

Solutions

  1. Pass a non-null lambda or delegate to Callback()
  2. Guard conditional callback selection so a default lambda is always provided
  3. If the callback is optional, skip calling .Callback() entirely instead of passing null

Example fix

// before
mock.Setup(m => m.DoWork()).Callback(optionalAction);
// after
mock.Setup(m => m.DoWork()).Callback(() => optionalAction?.Invoke());
Defensive patterns

Strategy: validation

Validate before calling

if (callback == null) throw new InvalidOperationException("Callback delegate must not be null before Setup");

Type guard

static bool IsValidCallback(Delegate? d) => d is not null;

Try / catch

try { setup.Callback(cb); } catch (ArgumentNullException ex) when (ex.ParamName == "callback") { /* supply a default lambda */ }

Prevention

When it happens

Trigger: Calling `.Callback(null)`, or passing a variable/ternary expression that evaluates to null, e.g. `.Callback(someCondition ? action1 : null)`.

Common situations: Conditionally selected callbacks where one branch is null; callbacks resolved from configuration or DI that weren't wired up.

Related errors


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

Appendix: source

Thrown at src/Moq/MethodCall.cs:144

            this.afterReturnCallback?.Execute(invocation);
        }

        public void SetCallBaseBehavior()
        {
            if (this.Mock.MockedType.IsDelegateType())
            {
                throw new NotSupportedException(Resources.CallBaseCannotBeUsedWithDelegateMocks);
            }

            this.returnOrThrow = ReturnBase.Instance;
        }

        public void SetCallbackBehavior(Delegate callback)
        {
            if (callback == null)
            {
                throw new ArgumentNullException(nameof(callback));
            }

            ref Behavior? behavior = ref (this.returnOrThrow == null) ? ref this.callback
                                                                     : ref this.afterReturnCallback;

            if (callback is Action callbackWithoutArguments)
            {
                behavior = new Callback(_ => callbackWithoutArguments());
            }
            else if (callback.GetType() == typeof(Action<IInvocation>))
            {
                // NOTE: Do NOT rewrite the above condition as `callback is Action<IInvocation>`,
                // because this will also yield true if `callback` is a `Action<object>` and thus
                // break existing uses of `(object arg) => ...` callbacks!
                behavior = new Callback((Action<IInvocation>)callback);
            }
            else
            {

View on GitHub (pinned to 89a5be629c)