oven-sh/bun · critical · CertError
CERT_REVOKED
CERT_REVOKED
Error message
CERT_REVOKED
What it means
CertError::CERT_REVOKED maps BoringSSL X509 verify code 23 (X509_V_ERR_CERT_REVOKED) via get_cert_error_from_no() in src/http/lib.rs:1542. During path validation a CRL covering the certificate listed its serial as revoked, so the TLS connection is rejected. JS error.code is CERT_REVOKED with message 'certificate revoked' (FetchTasklet.rs:1437).
Source
Thrown at src/http/error.rs:167
#[error("ERROR_IN_CERT_NOT_AFTER_FIELD")]
ERROR_IN_CERT_NOT_AFTER_FIELD,
#[error("ERROR_IN_CRL_LAST_UPDATE_FIELD")]
ERROR_IN_CRL_LAST_UPDATE_FIELD,
#[error("ERROR_IN_CRL_NEXT_UPDATE_FIELD")]
ERROR_IN_CRL_NEXT_UPDATE_FIELD,
#[error("OUT_OF_MEM")]
OUT_OF_MEM,
#[error("DEPTH_ZERO_SELF_SIGNED_CERT")]
DEPTH_ZERO_SELF_SIGNED_CERT,
#[error("SELF_SIGNED_CERT_IN_CHAIN")]
SELF_SIGNED_CERT_IN_CHAIN,
#[error("UNABLE_TO_GET_ISSUER_CERT_LOCALLY")]
UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
#[error("UNABLE_TO_VERIFY_LEAF_SIGNATURE")]
UNABLE_TO_VERIFY_LEAF_SIGNATURE,
#[error("CERT_CHAIN_TOO_LONG")]
CERT_CHAIN_TOO_LONG,
#[error("CERT_REVOKED")]
CERT_REVOKED,
#[error("INVALID_CA")]
INVALID_CA,
#[error("PATH_LENGTH_EXCEEDED")]
PATH_LENGTH_EXCEEDED,
#[error("INVALID_PURPOSE")]
INVALID_PURPOSE,
#[error("CERT_UNTRUSTED")]
CERT_UNTRUSTED,
#[error("CERT_REJECTED")]
CERT_REJECTED,
#[error("SUBJECT_ISSUER_MISMATCH")]
SUBJECT_ISSUER_MISMATCH,
#[error("AKID_SKID_MISMATCH")]
AKID_SKID_MISMATCH,
#[error("AKID_ISSUER_SERIAL_MISMATCH")]
AKID_ISSUER_SERIAL_MISMATCH,
#[error("KEYUSAGE_NO_CERTSIGN")]View on GitHub (pinned to 8c5296ac45)
Solutions
- Check the CA's revocation status page / crt.sh for the cert serial, then request and install a fresh certificate
- If an intermediate was revoked, get the server reissued under a different intermediate and serve the new chain
- Confirm it is not a stale-CRL artifact: openssl verify -crl_check -CRLfile crl.pem leaf.pem
- Only for throwaway test endpoints: tls: { rejectUnauthorized: false } — never in production
Example fix
// before
await fetch("https://revoked.example.com");
// after (test only): acknowledge revocation explicitly
await fetch("https://revoked.example.com", {
tls: { rejectUnauthorized: false }, // test env only
}); Defensive patterns
Strategy: try-catch
Validate before calling
import tls from "node:tls";
function ocspOk(host: string, port = 443): Promise<boolean> {
return new Promise((resolve) => {
const s = tls.connect({ host, port, servername: host }, () => { resolve(s.authorized); s.destroy(); });
s.on("error", (err: any) => resolve(err?.code !== "CERT_REVOKED"));
});
}
const ok = await ocspOk("partner.example.com"); Type guard
function isCertRevoked(e: unknown): e is Error & { code: "CERT_REVOKED" } {
return e instanceof Error && (e as any).code === "CERT_REVOKED";
} Try / catch
try { return await fetch(url); } catch (e) { if (isCertRevoked(e)) { quarantineHost(new URL(url).host); throw new Error(`refusing revoked endpoint: ${url}`); } throw e; } Prevention
- Subscribe to CA revocation/downtime notices for certs you depend on
- Cache last-known-good responses so a revoked upstream degrades gracefully
- Never catch CERT_REVOKED and retry to a bypassed verification path
When it happens
Trigger: TLS handshake against a server whose certificate (or an intermediate in its chain) was revoked by the CA's CRL; CRL data supplied in the verification context matches the cert's serial number.
Common situations: CA revoked the cert after compromise or mis-issuance and the operator missed the notice; test/lab CA with a stale CRL that accidentally lists the serial; revocation of an intermediate taking down all leafs under it.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- INVALID_EXTENSION
- DIFFERENT_CRL_SCOPE
- CRL_PATH_VALIDATION_ERROR
- UNABLE_TO_GET_CRL
- UNABLE_TO_DECRYPT_CRL_SIGNATURE
AI-assisted analysis of oven-sh/bun@8c5296ac45 (2026-08-16).
Data as JSON: /api/errors/5720a479f1f669fb.
Report an issue: GitHub.