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

  1. Inspect the leaf: openssl x509 -in leaf.pem -text -noout | grep -A1 'Extended Key Usage' — it must include TLS Web Server Authentication
  2. Reissue the cert with extendedKeyUsage=serverAuth (plus clientAuth if used for mTLS)
  3. If the CA enforces EKU constraints, reissue from a CA whose EKUs include serverAuth
  4. 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

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


AI-assisted analysis of oven-sh/bun@8c5296ac45 (2026-08-16). Data as JSON: /api/errors/666ef1f29d506b51. Report an issue: GitHub.