oven-sh/bun · error · CertError

PATH_LENGTH_EXCEEDED

PATH_LENGTH_EXCEEDED

Error message

PATH_LENGTH_EXCEEDED

What it means

CertError::PATH_LENGTH_EXCEEDED maps BoringSSL X509 verify code 25 (X509_V_ERR_PATH_LENGTH_EXCEEDED) via get_cert_error_from_no() in src/http/lib.rs:1544. An intermediate's Basic Constraints pathlen (path length constraint) is smaller than the number of CA certificates that follow it in the chain, so path building fails. JS error.code is PATH_LENGTH_EXCEEDED with message 'path length constraint exceeded' (FetchTasklet.rs:1446).

Source

Thrown at src/http/error.rs:171

    #[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")]
    KEYUSAGE_NO_CERTSIGN,
    #[error("UNABLE_TO_GET_CRL_ISSUER")]
    UNABLE_TO_GET_CRL_ISSUER,
    #[error("UNHANDLED_CRITICAL_EXTENSION")]

View on GitHub (pinned to 8c5296ac45)

Solutions

  1. Inspect pathlen of every served intermediate: openssl x509 -in int.pem -text -noout | grep -A1 'Path Len'
  2. Serve the chain that avoids the constrained intermediate (pick the alternate path that satisfies pathlen)
  3. Ask the CA to reissue the intermediate with a sufficient pathlen (or pathlen absent)
  4. Restructure the PKI so leafs are issued directly from the pathlen-limited CA

Example fix

# before: chain root -> intA(pathlen:0) -> intB -> leaf  (rejected)
# after: reissue leaf directly under intA
openssl x509 -req -in leaf.csr -CA intA.pem -CAkey intA-key.pem \
  -extfile <(printf 'basicConstraints=CA:FALSE
keyUsage=digitalSignature,keyEncipherment
extendedKeyUsage=serverAuth') \
  -out leaf.pem -days 390
Defensive patterns

Strategy: try-catch

Validate before calling

import { X509Certificate } from "node:crypto";
const int = new X509Certificate(await Bun.file("intermediate.pem").text());
// X509Certificate exposes ca but not pathlen; parse it for ops checks:
import { execSync } from "node:child_process";
const pathlen = execSync("openssl x509 -in intermediate.pem -noout -text").toString().match(/pathlen:(\d+)/)?.[1];
if (pathlen !== undefined && Number(pathlen) < 1 && process.env.REQUIRES_SUB_CA === "1") {
  throw new Error("intermediate pathlen forbids sub-CAs — pick another chain");
}

Type guard

function isPathLengthExceeded(e: unknown): e is Error & { code: "PATH_LENGTH_EXCEEDED" } {
  return e instanceof Error && (e as any).code === "PATH_LENGTH_EXCEEDED";
}

Try / catch

try { await fetch(url); } catch (e) { if (isPathLengthExceeded(e)) { alertPkiTeam("pathlen violated on chain for " + new URL(url).host); return useDirectLeafChain(url); } throw e; }

Prevention

When it happens

Trigger: Chain contains an intermediate with pathlen:0 (or 1) followed by additional intermediate CA(s); e.g., leaf <- sub-CA-A(pathlen:0) <- sub-CA-B <- root, where A cannot have another CA below it.

Common situations: Internal PKI teams delegate an 'issuing CA' with pathlen:0 and then later create sub-CAs beneath it; wrong intermediate from a cross-signed hierarchy served in the chain; CA templates with overly restrictive pathlen.

Related errors


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