oven-sh/bun · error · CertError
INVALID_PURPOSE
INVALID_PURPOSE
Error message
INVALID_PURPOSE
What it means
CertError::INVALID_PURPOSE maps BoringSSL X509 verify code 26 (X509_V_ERR_INVALID_PURPOSE) via get_cert_error_from_no() in src/http/lib.rs:1545. The certificate's Key Usage or Extended Key Usage does not permit the purpose it is being validated for (TLS server authentication of the fetch target). JS error.code is INVALID_PURPOSE with message 'unsupported certificate purpose' (FetchTasklet.rs:1457).
Source
Thrown at src/http/error.rs:173
#[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")]
KEYUSAGE_NO_CERTSIGN,
#[error("UNABLE_TO_GET_CRL_ISSUER")]
UNABLE_TO_GET_CRL_ISSUER,
#[error("UNHANDLED_CRITICAL_EXTENSION")]
UNHANDLED_CRITICAL_EXTENSION,
#[error("KEYUSAGE_NO_CRL_SIGN")]View on GitHub (pinned to 8c5296ac45)
Solutions
- Inspect the leaf: openssl x509 -in leaf.pem -text -noout | grep -A1 'Extended Key Usage' — it must include TLS Web Server Authentication
- Reissue the cert with extendedKeyUsage=serverAuth (plus clientAuth if used for mTLS)
- If the CA enforces EKU constraints, reissue from a CA whose EKUs include serverAuth
- Stop reusing certs across purposes; one cert, one role
Example fix
# before: CSR signed without EKU openssl x509 -req -in server.csr -CA ca.pem -CAkey ca.key -out server.pem # after: include server EKU openssl x509 -req -in server.csr -CA ca.pem -CAkey ca.key -out server.pem \ -extfile <(printf 'extendedKeyUsage=serverAuth keyUsage=digitalSignature,keyEncipherment')
Defensive patterns
Strategy: validation
Validate before calling
import { X509Certificate } from "node:crypto";
const cert = new X509Certificate(await Bun.file("server.pem").text());
const eku = (cert as any).keyUsage ?? ""; // node exposes keyUsage string
const x509text = await Bun.$`openssl x509 -in server.pem -noout -text`.text();
if (!/TLS Web Server Authentication/.test(x509text)) {
throw new Error("server.pem lacks serverAuth EKU — fetch will fail INVALID_PURPOSE");
} Type guard
function isInvalidPurpose(e: unknown): e is Error & { code: "INVALID_PURPOSE" } {
return e instanceof Error && (e as any).code === "INVALID_PURPOSE";
} Try / catch
try { await fetch(url); } catch (e) { if (isInvalidPurpose(e)) { openCertTicket(new URL(url).host, "missing serverAuth EKU"); throw e; } throw e; } Prevention
- Certificate templates must pin extendedKeyUsage=serverAuth for TLS endpoints
- Never reuse client/VPN/signing certs on servers
- Add a cert-lint step (openssl x509 -text grep) to your issuance pipeline
When it happens
Trigger: Server presents a client-auth-only, code-signing, S/MIME, or OCSP-signing certificate where a TLS server cert is required; a CA in the chain carries EKU restrictions that exclude serverAuth so leafs under it fail purpose checks.
Common situations: Reusing a client VPN/mTLS cert on the server side, internal tooling issuing certs from a template without extendedKeyUsage=serverAuth, CAs whose EKU constraints propagate down the chain.
Related errors
- UNABLE_TO_VERIFY_LEAF_SIGNATURE
- CERT_CHAIN_TOO_LONG
- INVALID_CA
- PATH_LENGTH_EXCEEDED
- SUBJECT_ISSUER_MISMATCH
AI-assisted analysis of oven-sh/bun@8c5296ac45 (2026-08-16).
Data as JSON: /api/errors/666ef1f29d506b51.
Report an issue: GitHub.