{"record":{"id":"d909ea81e124a0c7","repo":"oven-sh/bun","slug":"unable-to-decrypt-cert-signature","errorCode":null,"errorMessage":"UNABLE_TO_DECRYPT_CERT_SIGNATURE","messagePattern":"UNABLE_TO_DECRYPT_CERT_SIGNATURE","errorType":"error_code","errorClass":"CertError","httpStatus":null,"severity":"error","filePath":"src/http/error.rs","lineNumber":129,"sourceCode":"    Zlib(bun_zlib::ZlibError),\n    #[error(transparent)]\n    Brotli(bun_brotli::Error),\n    #[error(transparent)]\n    Zstd(bun_zstd::ZstdError),\n    #[error(transparent)]\n    Picohttp(bun_picohttp::ParseResponseError),\n}\n\n#[allow(non_camel_case_types)]\n#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error, strum::IntoStaticStr)]\npub enum CertError {\n    #[error(\"OK\")]\n    OK,\n    #[error(\"UNABLE_TO_GET_ISSUER_CERT\")]\n    UNABLE_TO_GET_ISSUER_CERT,\n    #[error(\"UNABLE_TO_GET_CRL\")]\n    UNABLE_TO_GET_CRL,\n    #[error(\"UNABLE_TO_DECRYPT_CERT_SIGNATURE\")]\n    UNABLE_TO_DECRYPT_CERT_SIGNATURE,\n    #[error(\"UNABLE_TO_DECRYPT_CRL_SIGNATURE\")]\n    UNABLE_TO_DECRYPT_CRL_SIGNATURE,\n    #[error(\"UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY\")]\n    UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY,\n    #[error(\"CERT_SIGNATURE_FAILURE\")]\n    CERT_SIGNATURE_FAILURE,\n    #[error(\"CRL_SIGNATURE_FAILURE\")]\n    CRL_SIGNATURE_FAILURE,\n    #[error(\"CERT_NOT_YET_VALID\")]\n    CERT_NOT_YET_VALID,\n    #[error(\"CERT_HAS_EXPIRED\")]\n    CERT_HAS_EXPIRED,\n    #[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\")]","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/oven-sh/bun/blob/8c5296ac459e8252d3cd702f3fbcbb0c249d95d5/src/http/error.rs#L111-L147","documentation":"X509 verify result 4 (X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE): the signature on a certificate could not be decrypted with the public key of its supposed issuer — the issuer certificate found does not actually sign this cert (or the cert bytes are corrupt). Mapped by get_cert_error_from_no (src/http/lib.rs:1523) to CertError::UNABLE_TO_DECRYPT_CERT_SIGNATURE, message \"unable to decrypt certificate's signature\" (FetchTasklet.rs:1382).","triggerScenarios":"fetch/https/Bun.connect TLS handshake where the chain the client assembles pairs the leaf with the wrong intermediate (cross-signed vs. modern issuer mixups), or the served certificate is truncated/corrupted.","commonSituations":"Servers serving an outdated cross-signed intermediate after a CA rotation (e.g. Let's Encrypt 2021 R3/E1 transitions), wrong-chain ordering in a PEM bundle, or a cert file corrupted during copy/paste (missing BEGIN/END lines).","solutions":["Regenerate/re-download the correct full chain from the CA and serve leaf + correct intermediates in order","Verify the file integrity: openssl x509 -in cert.pem -noout -text parses cleanly, and openssl verify -CAfile chain.pem cert.pem succeeds","If a stale cross-signed intermediate is cached client-side, clear it / pass the current intermediate via tls.ca","For internal PKIs, confirm the leaf was signed by the intermediate actually being served"],"exampleFix":"# diagnose\nopenssl s_client -connect example.com:443 -showcerts\nopenssl verify -CAfile <(cat intermediate.pem root.pem) leaf.pem","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isCertErrorCode(e: unknown, code = \"UNABLE_TO_DECRYPT_CERT_SIGNATURE\"): e is Error & { code: string } {\n  return e instanceof Error && (e as any).code === code;\n}","tryCatchPattern":"try {\n  await fetch(url);\n} catch (e) {\n  if (isCertErrorCode(e, \"UNABLE_TO_DECRYPT_CERT_SIGNATURE\")) {\n    // wrong intermediate paired with leaf — fix on the server; not transient, don't blind-retry\n    throw new Error(\"Server presents a mismatched certificate chain\");\n  }\n  throw e;\n}","preventionTips":["Automate chain assembly from the CA (download intermediates at issuance, serve in order)","After every cert rotation, verify with openssl verify -CAfile chain leaf before deploying","Never hand-stitch PEM bundles from different issuance eras"],"tags":["tls","certificates","pkix","fetch","network"],"backgroundTag":null,"analyzedSha":"8c5296ac459e8252d3cd702f3fbcbb0c249d95d5","analyzedAt":"2026-08-16T08:01:58.794Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}