JuliusBrussee/caveman · error
: certificate is unparseable, so the bundle is incomplete…
Error message
%s: certificate %d is unparseable, so the bundle is incomplete and must not be half-trusted: %w
What it means
Certificates parses a PEM file at path; when a CERTIFICATE block's DER bytes fail x509.ParseCertificate, it fails closed instead of skipping the bad entry, since trusting the remaining certs would make the bundle incomplete and half-trusted. The error names the file, the 1-based certificate position, and wraps the underlying parse error.
Solutions
- Verify each PEM block with `openssl x509 -in bundle.pem` per block (or `openssl crl2pkcs7 -nocrl -certfile bundle.pem | openssl pkcs7 -print_certs`) to find the corrupt certificate.
- Re-export/re-download the offending certificate from its source; replace the file rather than editing base64 by hand.
- Check the number of certs (openssl grep -c 'BEGIN CERTIFICATE') against what the CA provided; a truncated copy/paste is the usual culprit.
- If the file is actually a private key or CSR, obtain the correct certificate file and update the configured path.
Example fix
// before
roots, err := cabundle.PoolOf(mustParse("/etc/certs/bundle.pem")) // cert #2 corrupt
// after
// regenerate bundle from known-good certs:
// cat root.pem intermediate.pem > bundle.pem && openssl x509 -in bundle.pem -noout
roots, err := cabundle.PoolOf(certs)
if err != nil { return fmt.Errorf("tls setup: %w", err) } Defensive patterns
Strategy: validation
Validate before calling
func validateBundle(path string) error {
data, err := os.ReadFile(path)
if err != nil { return err }
rest := data
for {
var block *pem.Block
block, rest = pem.Decode(rest)
if block == nil { break }
if block.Type != "CERTIFICATE" { continue }
if _, err := x509.ParseCertificate(block.Bytes); err != nil {
return fmt.Errorf("%s has a corrupt certificate: %w", path, err)
}
}
return nil
}
// call validateBundle before cabundle.Certificates/PoolOf Try / catch
certs, err := cabundle.Certificates(path)
if err != nil && strings.Contains(err.Error(), "unparseable") {
return fmt.Errorf("TLS bundle %s is corrupt; regenerate it from the CA source: %w", path, err)
} Prevention
- Validate bundles with `openssl x509`/`crl2pkcs7` in CI before deploying.
- Never paste-edit base64; always regenerate files from the CA's original output.
- Verify the file is a certificate bundle, not a key or CSR (block type check).
- Keep the app fail-closed: never strip bad certs to 'make it work'.
When it happens
Trigger: Calling Certificates (or Pool/loadRootCAs which call it) on a PEM file containing a block labeled CERTIFICATE whose bytes are corrupt, truncated, or not DER (e.g. the file contains a PRIVATE KEY body mislabeled, or was mangled by copy-paste/encoding conversion).
Common situations: Mounting a truncated Kubernetes secret or ConfigMap; a cert file saved with Windows line-ending or base64 re-encoding corruption; concatenating a full-chain file where one intermediate was cut off mid-base64; passing a private key file where a certificate was expected.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- : trailing PEM block is truncated after certificate(s), so…
- contains no valid PEM certificate
- load system certificate pool
- bedrock request path
- ca_bundle
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/af609a56bde79eeb.
Report an issue: GitHub.
Appendix: source
Thrown at shared/platform/cabundle/cabundle.go:69
func Certificates(path string) ([]*x509.Certificate, error) {
bundle, err := os.ReadFile(path)
if err != nil {
return nil, err
}
var certs []*x509.Certificate
rest := bundle
for {
var block *pem.Block
block, rest = pem.Decode(rest)
if block == nil {
break
}
if block.Type != "CERTIFICATE" {
continue
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, fmt.Errorf("%s: certificate %d is unparseable, so the bundle is incomplete and must not be half-trusted: %w", path, len(certs)+1, err)
}
certs = append(certs, cert)
}
if bytes.Contains(rest, []byte("-----BEGIN")) {
return nil, fmt.Errorf("%s: trailing PEM block is truncated after %d certificate(s), so the bundle is incomplete and must not be half-trusted", path, len(certs))
}
if len(certs) == 0 {
return nil, fmt.Errorf("%s contains no valid PEM certificate", path)
}
return certs, nil
}
View on GitHub (pinned to 3ee70a1026)