nodejs/node · error · InvalidArgumentError

Proxy opts.clientFactory must be a function.

Error message

Proxy opts.clientFactory must be a function.

What it means

Thrown by the ProxyAgent constructor when opts.clientFactory is present but not a function. clientFactory lets callers supply a custom Dispatcher constructor for the underlying connection (e.g. Pool, Agent, or a test double); a non-callable value cannot produce a dispatcher so construction is aborted. The default is defaultFactory when the key is absent.

Source

Thrown at deps/undici/src/lib/dispatcher/proxy-agent.js:118

  [kClose] () {
    return this.#client.close()
  }

  [kDestroy] (err) {
    return this.#client.destroy(err)
  }
}

class ProxyAgent extends DispatcherBase {
  constructor (opts) {
    if (!opts || (typeof opts === 'object' && !(opts instanceof URL) && !opts.uri)) {
      throw new InvalidArgumentError('Proxy uri is mandatory')
    }

    const { clientFactory = defaultFactory } = opts
    if (typeof clientFactory !== 'function') {
      throw new InvalidArgumentError('Proxy opts.clientFactory must be a function.')
    }

    const { proxyTunnel, connectTimeout } = opts

    super()

    const url = this.#getUrl(opts)
    const { href, origin, port, protocol, username, password, hostname: proxyHostname } = url

    this[kProxy] = { uri: href, protocol }
    this[kRequestTls] = opts.requestTls
    this[kProxyTls] = opts.proxyTls
    this[kProxyHeaders] = opts.headers || {}
    this[kTunnelProxy] = proxyTunnel

    if (opts.auth && opts.token) {
      throw new InvalidArgumentError('opts.auth cannot be used in combination with opts.token')
    } else if (opts.auth) {

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Pass the class/function reference itself: clientFactory: Pool, not clientFactory: new Pool().
  2. Omit clientFactory to use the built-in defaultFactory.
  3. If using a custom factory, ensure it has signature (url, opts) => Dispatcher.
  4. Avoid putting clientFactory in plain JSON config; load it from code.

Example fix

// before
new ProxyAgent({ uri, clientFactory: new Pool(origin) })
// after
new ProxyAgent({ uri, clientFactory: (origin, opts) => new Pool(origin, opts) })
Defensive patterns

Strategy: type-guard

Validate before calling

if (cfg.clientFactory != null && typeof cfg.clientFactory !== 'function') {
  throw new TypeError('clientFactory must be a function/class reference, not an instance')
}
new ProxyAgent({ uri, clientFactory: cfg.clientFactory })

Type guard

function isClientFactory(v) { return v == null || typeof v === 'function' }

Prevention

When it happens

Trigger: Passing clientFactory as a string, object, or the result of invoking a factory instead of the factory itself. The destructuring default clientFactory = defaultFactory only applies when the key is absent, so an explicit non-function value bypasses the default and hits the guard.

Common situations: Writing clientFactory: Pool (correct, a function/class) vs clientFactory: new Pool(...) (wrong, an instance); JSON config that decoded clientFactory to a string; refactoring that wraps the factory in an options object.

Related errors


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