nodejs/node · error · InvalidArgumentError

UND_ERR_INVALID_ARG

UND_ERR_INVALID_ARG

Error message

Argument opts.agent must implement Agent

What it means

Thrown by the `MockAgent` constructor (`InvalidArgumentError`, code `UND_ERR_INVALID_ARG`) when `opts.agent` is provided but does not expose a `dispatch` function. `MockAgent` wraps a real dispatcher (defaulting to a new `Agent`) and routes intercepted dispatches through it for non-mocked origins; it probes the supplied object for `dispatch` to confirm it is a Dispatcher-compatible agent. Anything lacking that method cannot be delegated to.

Source

Thrown at deps/undici/src/lib/mock/mock-agent.js:45

const Dispatcher = require('../dispatcher/dispatcher')
const PendingInterceptorsFormatter = require('./pending-interceptors-formatter')
const { MockCallHistory } = require('./mock-call-history')

class MockAgent extends Dispatcher {
  constructor (opts = {}) {
    super(opts)

    const mockOptions = buildAndValidateMockOptions(opts)

    this[kNetConnect] = true
    this[kIsMockActive] = true
    this[kMockAgentIsCallHistoryEnabled] = mockOptions.enableCallHistory ?? false
    this[kMockAgentAcceptsNonStandardSearchParameters] = mockOptions.acceptNonStandardSearchParameters ?? false
    this[kIgnoreTrailingSlash] = mockOptions.ignoreTrailingSlash ?? false

    // Instantiate Agent and encapsulate
    if (opts?.agent && typeof opts.agent.dispatch !== 'function') {
      throw new InvalidArgumentError('Argument opts.agent must implement Agent')
    }
    const agent = opts?.agent ? opts.agent : new Agent(opts)
    this[kAgent] = agent

    this[kClients] = agent[kClients]
    this[kOptions] = mockOptions

    if (this[kMockAgentIsCallHistoryEnabled]) {
      this[kMockAgentRegisterCallHistory]()
    }
  }

  get (origin) {
    // Normalize origin to handle URL objects and case-insensitive hostnames
    const normalizedOrigin = normalizeOrigin(origin)
    const originKey = this[kIgnoreTrailingSlash] ? normalizedOrigin.replace(/\/$/, '') : normalizedOrigin

    let dispatcher = this[kMockAgentGet](originKey)

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Pass an actual undici `Agent` (or any object exposing `dispatch(opts, handler)`), e.g. `new MockAgent({ agent: existingAgent })`.
  2. If you only want to configure the underlying agent, pass those options directly to `MockAgent` and let it construct the inner `Agent` itself.
  3. For custom dispatchers, ensure they expose a `dispatch` method matching the Dispatcher contract.

Example fix

// before
const agent = new MockAgent({ agent: { connections: 10 } })
const agent = new MockAgent({ agent: somePool }) // no dispatch

// after
const agent = new MockAgent({ agent: new Agent({ connections: 10 }) })
// or let MockAgent build it:
const agent = new MockAgent({ connections: 10 })
Defensive patterns

Strategy: type-guard

Validate before calling

function resolveAgent(candidate) {
  if (candidate == null) return undefined
  if (typeof candidate.dispatch !== 'function') {
    throw new Error('opts.agent must expose a dispatch(opts, handler) function')
  }
  return candidate
}

Type guard

function isDispatcherLike(v) {
  return v != null && typeof v.dispatch === 'function'
}

Prevention

When it happens

Trigger: Passing `agent: new URL(...)`, an options object, a plain `{ connections: 10 }` (the opts, not an agent), or a custom object that forgot to implement `dispatch`. The guard is `opts?.agent && typeof opts.agent.dispatch !== 'function'`. Note the check is duck-typed on the `dispatch` method, not on `instanceof Agent`.

Common situations: Passing the agent options object where the agent instance belongs; wrapping a custom Dispatcher subclass that did not expose `dispatch`; passing a Proxy agent or Pool where the consumer expected an Agent; copy-paste from examples that use a different variable name.

Related errors


AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13). Data as JSON: /api/errors/4c1eda77d384f48c. Report an issue: GitHub.