{"record":{"id":"91b85d2fd8feafa1","repo":"nodejs/node","slug":"proxy-opts-clientfactory-must-be-a-function","errorCode":null,"errorMessage":"Proxy opts.clientFactory must be a function.","messagePattern":"Proxy opts\\.clientFactory must be a function\\.","errorType":"exception","errorClass":"InvalidArgumentError","httpStatus":null,"severity":"error","filePath":"deps/undici/src/lib/dispatcher/proxy-agent.js","lineNumber":118,"sourceCode":"\n  [kClose] () {\n    return this.#client.close()\n  }\n\n  [kDestroy] (err) {\n    return this.#client.destroy(err)\n  }\n}\n\nclass ProxyAgent extends DispatcherBase {\n  constructor (opts) {\n    if (!opts || (typeof opts === 'object' && !(opts instanceof URL) && !opts.uri)) {\n      throw new InvalidArgumentError('Proxy uri is mandatory')\n    }\n\n    const { clientFactory = defaultFactory } = opts\n    if (typeof clientFactory !== 'function') {\n      throw new InvalidArgumentError('Proxy opts.clientFactory must be a function.')\n    }\n\n    const { proxyTunnel, connectTimeout } = opts\n\n    super()\n\n    const url = this.#getUrl(opts)\n    const { href, origin, port, protocol, username, password, hostname: proxyHostname } = url\n\n    this[kProxy] = { uri: href, protocol }\n    this[kRequestTls] = opts.requestTls\n    this[kProxyTls] = opts.proxyTls\n    this[kProxyHeaders] = opts.headers || {}\n    this[kTunnelProxy] = proxyTunnel\n\n    if (opts.auth && opts.token) {\n      throw new InvalidArgumentError('opts.auth cannot be used in combination with opts.token')\n    } else if (opts.auth) {","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/deps/undici/src/lib/dispatcher/proxy-agent.js#L100-L136","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nnew ProxyAgent({ uri, clientFactory: new Pool(origin) })\n// after\nnew ProxyAgent({ uri, clientFactory: (origin, opts) => new Pool(origin, opts) })","handlingStrategy":"type-guard","validationCode":"if (cfg.clientFactory != null && typeof cfg.clientFactory !== 'function') {\n  throw new TypeError('clientFactory must be a function/class reference, not an instance')\n}\nnew ProxyAgent({ uri, clientFactory: cfg.clientFactory })","typeGuard":"function isClientFactory(v) { return v == null || typeof v === 'function' }","tryCatchPattern":null,"preventionTips":["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."],"tags":["undici","proxy","proxy-agent","factory","invalid-arg"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}