{"record":{"id":"58035e6e6a522b70","repo":"oven-sh/bun","slug":"invalid-non-ca","errorCode":"INVALID_NON_CA","errorMessage":"INVALID_NON_CA","messagePattern":"INVALID_NON_CA","errorType":"error_code","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/http/error.rs","lineNumber":195,"sourceCode":"    #[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\")]\n    PROXY_PATH_LENGTH_EXCEEDED,\n    #[error(\"KEYUSAGE_NO_DIGITAL_SIGNATURE\")]\n    KEYUSAGE_NO_DIGITAL_SIGNATURE,\n    #[error(\"PROXY_CERTIFICATES_NOT_ALLOWED\")]\n    PROXY_CERTIFICATES_NOT_ALLOWED,\n    #[error(\"INVALID_EXTENSION\")]\n    INVALID_EXTENSION,\n    #[error(\"INVALID_POLICY_EXTENSION\")]\n    INVALID_POLICY_EXTENSION,\n    #[error(\"NO_EXPLICIT_POLICY\")]\n    NO_EXPLICIT_POLICY,\n    #[error(\"DIFFERENT_CRL_SCOPE\")]\n    DIFFERENT_CRL_SCOPE,\n    #[error(\"UNSUPPORTED_EXTENSION_FEATURE\")]\n    UNSUPPORTED_EXTENSION_FEATURE,\n    #[error(\"UNNESTED_RESOURCE\")]","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/oven-sh/bun/blob/8c5296ac459e8252d3cd702f3fbcbb0c249d95d5/src/http/error.rs#L177-L213","documentation":"CertError::INVALID_NON_CA maps BoringSSL X509 verify code 37 (X509_V_ERR_INVALID_NON_CA) via get_cert_error_from_no() in src/http/lib.rs:1556. A certificate in the middle of the chain (not the trust anchor, not self-issued) carries CA:TRUE Basic Constraints when it must not act as a CA, so the chain is rejected as malformed. JS error.code is INVALID_NON_CA with message 'invalid non-CA certificate (has CA markings)' (FetchTasklet.rs:1443).","triggerScenarios":"Leaf/intermediate certificate erroneously issued with basicConstraints=CA:TRUE (or CA markup) appears as a non-terminal link in the presented chain; commonly a server cert template that inherited CA flags.","commonSituations":"Misissued internal certs where the template copied CA extensions, chains hand-assembled with an extra CA-marked leaf appended, CA tooling bugs marking intermediates from non-CA profiles.","solutions":["Find which chain element has CA:TRUE but is not the anchor: openssl x509 -in cert.pem -noout -text | grep -A2 'Basic Constraints' for each cert in order","Reissue that certificate with basicConstraints=CA:FALSE (server leafs normally omit or set CA:FALSE)","Rebuild fullchain.pem with only properly-issued certs and reload the server","Re-test: openssl s_client -connect host:443 -brief </dev/null"],"exampleFix":"# before: leaf mistakenly issued with CA:TRUE\n[ext]\nbasicConstraints=critical,CA:TRUE,pathlen:1\n# after\n[ext]\nbasicConstraints=critical,CA:FALSE\nkeyUsage=critical,digitalSignature,keyEncipherment\nextendedKeyUsage=serverAuth","handlingStrategy":"validation","validationCode":"import { X509Certificate } from \"node:crypto\";\nfor (const f of [\"leaf.pem\", \"intermediate.pem\"]) {\n  const cert = new X509Certificate(await Bun.file(f).text());\n  if (f === \"leaf.pem\" && cert.ca) {\n    throw new Error(\"leaf must not carry CA:TRUE — INVALID_NON_CA will fail verification\");\n  }\n}","typeGuard":"function isInvalidNonCa(e: unknown): e is Error & { code: \"INVALID_NON_CA\" } {\n  return e instanceof Error && (e as any).code === \"INVALID_NON_CA\";\n}","tryCatchPattern":"try { await fetch(url); } catch (e) { if (isInvalidNonCa(e)) { notifyCertOwner(new URL(url).host, \"CA markings on non-CA cert\"); throw e; } throw e; }","preventionTips":["Separate CA and server templates; never clone CA profiles for leafs","Assert leaf X509Certificate#ca is false in issuance lint","Audit chains with openssl x509 -text for stray CA:TRUE flags"],"tags":["tls","certificate","pki","basic-constraints","chain"],"backgroundTag":null,"analyzedSha":"8c5296ac459e8252d3cd702f3fbcbb0c249d95d5","analyzedAt":"2026-08-16T08:01:58.794Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}