{"record":{"id":"9d1d2b7fb499da83","repo":"oven-sh/bun","slug":"subject-issuer-mismatch","errorCode":"SUBJECT_ISSUER_MISMATCH","errorMessage":"SUBJECT_ISSUER_MISMATCH","messagePattern":"SUBJECT_ISSUER_MISMATCH","errorType":"error_code","errorClass":"CertError","httpStatus":null,"severity":"error","filePath":"src/http/error.rs","lineNumber":179,"sourceCode":"    #[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\")]\n    SUBJECT_ISSUER_MISMATCH,\n    #[error(\"AKID_SKID_MISMATCH\")]\n    AKID_SKID_MISMATCH,\n    #[error(\"AKID_ISSUER_SERIAL_MISMATCH\")]\n    AKID_ISSUER_SERIAL_MISMATCH,\n    #[error(\"KEYUSAGE_NO_CERTSIGN\")]\n    KEYUSAGE_NO_CERTSIGN,\n    #[error(\"UNABLE_TO_GET_CRL_ISSUER\")]\n    UNABLE_TO_GET_CRL_ISSUER,\n    #[error(\"UNHANDLED_CRITICAL_EXTENSION\")]\n    UNHANDLED_CRITICAL_EXTENSION,\n    #[error(\"KEYUSAGE_NO_CRL_SIGN\")]\n    KEYUSAGE_NO_CRL_SIGN,\n    #[error(\"UNHANDLED_CRITICAL_CRL_EXTENSION\")]\n    UNHANDLED_CRITICAL_CRL_EXTENSION,\n    #[error(\"INVALID_NON_CA\")]\n    INVALID_NON_CA,\n    #[error(\"PROXY_PATH_LENGTH_EXCEEDED\")]","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/oven-sh/bun/blob/8c5296ac459e8252d3cd702f3fbcbb0c249d95d5/src/http/error.rs#L161-L197","documentation":"CertError::SUBJECT_ISSUER_MISMATCH maps BoringSSL X509 verify code 29 (X509_V_ERR_SUBJECT_ISSUER_MISMATCH) via get_cert_error_from_no() in src/http/lib.rs:1548. The issuer DN on a certificate does not match the subject DN of the certificate that follows it in the presented chain, so the chain does not link up. JS error.code is SUBJECT_ISSUER_MISMATCH with message 'subject issuer mismatch' (FetchTasklet.rs:1469).","triggerScenarios":"Server serves the wrong intermediate (one whose subject differs from the leaf's issuer field); chain PEMs concatenated out of order; certificate renewed under a different CA name but old intermediate still bundled.","commonSituations":"Certbot renewal switched intermediates (e.g., R10 -> R11) while nginx still serves the stale chain, manual fullchain assembly mixing cert generations, multi-CDN setups pasting mismatched bundles.","solutions":["Extract the leaf's issuer DN: openssl x509 -in leaf.pem -noout -issuer and the next cert's subject: openssl x509 -in int.pem -noout -subject — they must be byte-identical","Regenerate fullchain.pem from the current CA bundle shipped with the new cert (leaf + its actual intermediate, correct order)","Restart/reload the server so the new chain is served","Validate end-to-end: openssl s_client -connect host:443 -brief </dev/null"],"exampleFix":"# before\nleaf.pem + old-intermediate.pem + old-root.pem\n# after (after renewal, intermediate changed)\nleaf.pem + R11-intermediate.pem\n# verify linkage\nopenssl verify -show_chain -untrusted R11-intermediate.pem leaf.pem","handlingStrategy":"validation","validationCode":"import { X509Certificate } from \"node:crypto\";\nconst leaf = new X509Certificate(await Bun.file(\"leaf.pem\").text());\nconst int = new X509Certificate(await Bun.file(\"intermediate.pem\").text());\nif (leaf.issuer !== int.subject) {\n  throw new Error(`chain broken: leaf issuer '${leaf.issuer}' != intermediate subject '${int.subject}'`);\n}","typeGuard":"function isSubjectIssuerMismatch(e: unknown): e is Error & { code: \"SUBJECT_ISSUER_MISMATCH\" } {\n  return e instanceof Error && (e as any).code === \"SUBJECT_ISSUER_MISMATCH\";\n}","tryCatchPattern":"try { await fetch(url); } catch (e) { if (isSubjectIssuerMismatch(e)) { purgeHostCache(new URL(url).host); notifyCertOwner(\"served chain does not link up\"); throw e; } throw e; }","preventionTips":["Regenerate fullchain.pem automatically on cert renewal (never hand-edit)","Assert leaf.issuer === intermediate.subject in deploy scripts using node:crypto X509Certificate","Poll your own endpoints with openssl s_client after deploys"],"tags":["tls","certificate","chain","pki","fetch"],"backgroundTag":null,"analyzedSha":"8c5296ac459e8252d3cd702f3fbcbb0c249d95d5","analyzedAt":"2026-08-16T08:01:58.794Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}