{"record":{"id":"d81c22f693ebb6f0","repo":"oven-sh/bun","slug":"unable-to-get-issuer-cert-locally","errorCode":"UNABLE_TO_GET_ISSUER_CERT_LOCALLY","errorMessage":"UNABLE_TO_GET_ISSUER_CERT_LOCALLY","messagePattern":"UNABLE_TO_GET_ISSUER_CERT_LOCALLY","errorType":"error_code","errorClass":"CertError","httpStatus":null,"severity":"error","filePath":"src/http/error.rs","lineNumber":161,"sourceCode":"    #[error(\"CRL_NOT_YET_VALID\")]\n    CRL_NOT_YET_VALID,\n    #[error(\"CRL_HAS_EXPIRED\")]\n    CRL_HAS_EXPIRED,\n    #[error(\"ERROR_IN_CERT_NOT_BEFORE_FIELD\")]\n    ERROR_IN_CERT_NOT_BEFORE_FIELD,\n    #[error(\"ERROR_IN_CERT_NOT_AFTER_FIELD\")]\n    ERROR_IN_CERT_NOT_AFTER_FIELD,\n    #[error(\"ERROR_IN_CRL_LAST_UPDATE_FIELD\")]\n    ERROR_IN_CRL_LAST_UPDATE_FIELD,\n    #[error(\"ERROR_IN_CRL_NEXT_UPDATE_FIELD\")]\n    ERROR_IN_CRL_NEXT_UPDATE_FIELD,\n    #[error(\"OUT_OF_MEM\")]\n    OUT_OF_MEM,\n    #[error(\"DEPTH_ZERO_SELF_SIGNED_CERT\")]\n    DEPTH_ZERO_SELF_SIGNED_CERT,\n    #[error(\"SELF_SIGNED_CERT_IN_CHAIN\")]\n    SELF_SIGNED_CERT_IN_CHAIN,\n    #[error(\"UNABLE_TO_GET_ISSUER_CERT_LOCALLY\")]\n    UNABLE_TO_GET_ISSUER_CERT_LOCALLY,\n    #[error(\"UNABLE_TO_VERIFY_LEAF_SIGNATURE\")]\n    UNABLE_TO_VERIFY_LEAF_SIGNATURE,\n    #[error(\"CERT_CHAIN_TOO_LONG\")]\n    CERT_CHAIN_TOO_LONG,\n    #[error(\"CERT_REVOKED\")]\n    CERT_REVOKED,\n    #[error(\"INVALID_CA\")]\n    INVALID_CA,\n    #[error(\"PATH_LENGTH_EXCEEDED\")]\n    PATH_LENGTH_EXCEEDED,\n    #[error(\"INVALID_PURPOSE\")]\n    INVALID_PURPOSE,\n    #[error(\"CERT_UNTRUSTED\")]\n    CERT_UNTRUSTED,\n    #[error(\"CERT_REJECTED\")]\n    CERT_REJECTED,\n    #[error(\"SUBJECT_ISSUER_MISMATCH\")]","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/oven-sh/bun/blob/8c5296ac459e8252d3cd702f3fbcbb0c249d95d5/src/http/error.rs#L143-L179","documentation":"X509 verify result 20 (X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY): the issuer of a certificate was found in the chain but the lookup against the local trust store failed — the chain's anchor (root) is not among the CAs the client trusts. Mapped via get_cert_error_from_no (src/http/lib.rs:1539) to CertError::UNABLE_TO_GET_ISSUER_CERT_LOCALLY. Distinct from UNABLE_TO_GET_ISSUER_CERT (2): here the chain is complete but untrusted locally.","triggerScenarios":"fetch/https/Bun.connect to a server whose certificate chains to a private CA that is not in Bun's default root store — corporate/internal PKIs, self-hosted service meshes, test CAs — with reject_unauthorized left at its default true.","commonSituations":"Corporate environments with a private root CA not installed system-wide, minimal Docker images (alpine/distroless) missing ca-certificates, custom Kubernetes cluster CAs, freshly built machines without the org's CA package.","solutions":["Trust the private CA in Bun: set NODE_EXTRA_CA_CERTS=/path/to/org-ca.pem or pass it per-request via fetch(url, { tls: { ca: orgCaPem } })","In containers, install ca-certificates and append the org CA to the system store (update-ca-certificates)","Or get the service a publicly-trusted cert (Let's Encrypt) so no custom trust is needed","Avoid rejectUnauthorized: false here — trusting the real CA is cheap and keeps verification on"],"exampleFix":"// before\nawait fetch(\"https://internal.corp.svc/api\"); // UNABLE_TO_GET_ISSUER_CERT_LOCALLY\n\n// after\nimport { readFileSync } from \"node:fs\";\nawait fetch(\"https://internal.corp.svc/api\", {\n  tls: { ca: readFileSync(\"./org-ca.pem\", \"utf8\") },\n});","handlingStrategy":"try-catch","validationCode":"// startup check: private CA present before any internal fetch\nimport { readFileSync } from \"node:fs\";\nconst CA_PATH = process.env.ORG_CA_PATH ?? \"./org-ca.pem\";\nexport const orgCa = readFileSync(CA_PATH, \"utf8\"); // throws at boot if missing — fail fast\n// then always: fetch(url, { tls: { ca: orgCa } })","typeGuard":"function isCertErrorCode(e: unknown, code = \"UNABLE_TO_GET_ISSUER_CERT_LOCALLY\"): e is Error & { code: string } {\n  return e instanceof Error && (e as any).code === code;\n}","tryCatchPattern":"try {\n  await fetch(\"https://internal.corp.svc/api\");\n} catch (e) {\n  if (isCertErrorCode(e, \"UNABLE_TO_GET_ISSUER_CERT_LOCALLY\")) {\n    // chain is complete but root not trusted locally — supply the org CA and retry once\n    const res = await fetch(\"https://internal.corp.svc/api\", { tls: { ca: orgCa } });\n  } else throw e;\n}","preventionTips":["Bake the org CA into Docker images (ca-certificates + update-ca-certificates, or NODE_EXTRA_CA_CERTS)","Fail fast at startup if required CA files are missing rather than at first internal request","Prefer trusting the real CA over rejectUnauthorized:false — verification stays intact"],"tags":["tls","certificates","trust-store","corporate","fetch","docker"],"backgroundTag":null,"analyzedSha":"8c5296ac459e8252d3cd702f3fbcbb0c249d95d5","analyzedAt":"2026-08-16T08:01:58.794Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}