{"record":{"id":"d65add2699b7289e","repo":"denoland/deno","slug":"dispatcher-connect-ca-must-be-a-string-buffer-or","errorCode":null,"errorMessage":"Dispatcher connect.ca must be a string, Buffer, or ArrayBuffer","messagePattern":"Dispatcher connect\\.ca must be a string, Buffer, or ArrayBuffer","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/internal/deps/undici/undici.js","lineNumber":39,"sourceCode":"  \"Deno.internal.node.undici.dispatcherOptions\",\n);\nconst kGlobalDispatcher = SymbolFor(\n  \"Deno.internal.node.undici.globalDispatcher\",\n);\n\nfunction normalizeCaCerts(ca) {\n  const certs = ArrayIsArray(ca) ? ca : [ca];\n  return ArrayPrototypeMap(certs, (cert) => {\n    if (typeof cert === \"string\") {\n      return cert;\n    }\n    if (isArrayBufferView(cert)) {\n      return new TextDecoder().decode(cert);\n    }\n    if (isAnyArrayBuffer(cert)) {\n      return new TextDecoder().decode(new Uint8Array(cert));\n    }\n    throw new TypeError(\n      \"Dispatcher connect.ca must be a string, Buffer, or ArrayBuffer\",\n    );\n  });\n}\n\nclass Agent {\n  constructor(options = { __proto__: null }) {\n    const connect = options.connect ?? { __proto__: null };\n    const dispatcherOptions = { __proto__: null };\n\n    if (connect.rejectUnauthorized === false) {\n      dispatcherOptions.unsafelyIgnoreCertificateErrors = true;\n    }\n\n    if (connect.ca !== undefined) {\n      dispatcherOptions.caCerts = normalizeCaCerts(connect.ca);\n    }\n","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/internal/deps/undici/undici.js#L21-L57","documentation":"In Deno's bundled undici, dispatcher/Agent options.connect.ca is normalized by normalizeCaCerts: each entry must be a PEM string, an ArrayBuffer view (Buffer/Uint8Array), or an ArrayBuffer; a non-array value is wrapped into a list automatically. Any other type (X509Certificate, KeyObject, number, plain object, URL) throws this TypeError - note it has no code property, unlike the node: errors.","triggerScenarios":"new Agent({ connect: { ca: new X509Certificate(pem) } }); ca: 123 from bad config; an array containing null or objects parsed from JSON; passing a Node https.Agent-style options object wholesale as connect options.","commonSituations":"Corporate MITM proxy setups injecting custom CAs; migrating Node fetch/undici configuration where ca shapes differ; config-driven HTTP clients where the CA field is optional and sometimes an object.","solutions":["Pass the PEM string or Buffer directly: connect: { ca: pem } (single values are fine - non-arrays are wrapped).","If you hold an X509Certificate, unwrap it: connect: { ca: cert.toString() } (toString returns the PEM).","Sanitize config before constructing the Agent: keep only string/Buffer entries and drop the rest."],"exampleFix":"// before\nconst agent = new Agent({ connect: { ca: new X509Certificate(pem) } });\n\n// after\nconst agent = new Agent({ connect: { ca: pem } }); // PEM string or Buffer\n// or, from an X509Certificate: connect: { ca: cert.toString() }","handlingStrategy":"validation","validationCode":"function normalizeCa(ca) {\n  const list = Array.isArray(ca) ? ca : [ca];\n  return list.filter((c) =>\n    typeof c === 'string' || ArrayBuffer.isView(c) || c instanceof ArrayBuffer\n  );\n}\nconst agent = new Agent({ connect: { ca: normalizeCa(config.ca) } });","typeGuard":"const isCaEntry = (v) =>\n  typeof v === 'string' || ArrayBuffer.isView(v) || v instanceof ArrayBuffer;","tryCatchPattern":"try {\n  new Agent({ connect: { ca } });\n} catch (err) {\n  if (err instanceof TypeError && /connect\\.ca/.test(err.message)) {\n    agent = new Agent({ connect: { ca: pemString } }); // fall back to raw PEM\n  } else {\n    throw err;\n  }\n}","preventionTips":["Store CAs as PEM strings in config and convert anything else at the edge.","Unwrap X509Certificate values with toString() before passing to undici connect options.","Unit-test config parsing so ca entries are always string, Buffer or ArrayBuffer."],"tags":["undici","agent","tls","ca-certificate","fetch","typeerror"],"backgroundTag":"tls-ca-certificate-config","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}