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
- Pass the class/function reference itself: clientFactory: Pool, not clientFactory: new Pool().
- Omit clientFactory to use the built-in defaultFactory.
- If using a custom factory, ensure it has signature (url, opts) => Dispatcher.
- 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
- Pass the class/function reference (e.g. Pool), never new Pool().
- Keep clientFactory in code, not JSON config.
- Omit the key to use the default factory when in doubt.
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
- opts.auth cannot be used in combination with opts.token
- Proxy-Authorization should be sent in ProxyAgent constructor
- UND_ERR_INVALID_ARG
- factory must be a function.
- Proxy URL is mandatory
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/91b85d2fd8feafa1.
Report an issue: GitHub.