JuliusBrussee/caveman · error

contains no valid PEM certificate

Error message

%s contains no valid PEM certificate

What it means

loadCertificates parses a PEM bundle file and returns an error when it decodes zero usable certificates. The library throws it fail-closed: a bundle with no valid PEM blocks cannot be trusted to seed a root-CA pool, so callers get an error instead of an empty trust set.

Solutions

  1. Point the bundle path at a real CA bundle (e.g. /etc/ssl/certs/ca-certificates.crt) or the system trust store.
  2. Open the file and verify it contains at least one complete '-----BEGIN CERTIFICATE-----' ... '-----END CERTIFICATE-----' block.
  3. Re-download or re-export the bundle; confirm it is PEM (base64 with BEGIN/END headers), not DER or HTML.
  4. If you only have DER, convert: openssl x509 -inform DER -in cert.der -out cert.pem.

Example fix

// before
pool, err := NewPool(WithBundle("./notes.txt")) // notes.txt has no PEM
// after
pool, err := NewPool(WithBundle("/etc/ssl/certs/ca-certificates.crt"))
Defensive patterns

Strategy: validation

Validate before calling

func hasPEM(path string) bool {
	b, err := os.ReadFile(path)
	return err == nil && bytes.Contains(b, []byte("-----BEGIN CERTIFICATE-----"))
}

Try / catch

certs, err := loadCertificates(path)
if err != nil {
	return fmt.Errorf("CA bundle unusable, refusing to start: %w", err)
}

Prevention

When it happens

Trigger: Calling loadRootCAs/Pool with a path whose file exists but contains no '-----BEGIN CERTIFICATE-----' blocks (e.g. an empty file, a text README, a private-key-only file, or a file with only truncated/garbage PEM).

Common situations: Config pointing at the wrong file (e.g. the key instead of the cert), an env var like SSL_CERT_FILE set to a nonexistent-format file, a bundle downloaded as HTML error page, or a truncated download leaving only partial PEM text (that case may instead hit the trailing-truncated error).

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.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/42dcf1b9072137c6. Report an issue: GitHub.

Appendix: source

Thrown at shared/platform/cabundle/cabundle.go:77

		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)