nats-io/nats-server · error

unexpected PEM certificate type: %s

Error message

unexpected PEM certificate type: %s

What it means

parseCertPEM decodes a PEM file expected to contain only CERTIFICATE blocks. When a PEM block of a different type (e.g. PRIVATE KEY, CERTIFICATE REQUEST) is found, it aborts because the file was passed as a CA trust store (ocsp ca_file) and non-certificate material cannot be trusted as an issuer.

Source

Thrown at server/ocsp.go:887

	return nil
}

func parseCertPEM(name string) ([]*x509.Certificate, error) {
	data, err := os.ReadFile(name)
	if err != nil {
		return nil, err
	}

	var pemBytes []byte

	var block *pem.Block
	for len(data) != 0 {
		block, data = pem.Decode(data)
		if block == nil {
			break
		}
		if block.Type != "CERTIFICATE" {
			return nil, fmt.Errorf("unexpected PEM certificate type: %s", block.Type)
		}

		pemBytes = append(pemBytes, block.Bytes...)
	}

	return x509.ParseCertificates(pemBytes)
}

// getOCSPIssuerLocally determines a leaf's issuer from locally configured certificates
func getOCSPIssuerLocally(trustedCAs []*x509.Certificate, certBundle []*x509.Certificate) (*x509.Certificate, error) {
	var vOpts x509.VerifyOptions
	var leaf *x509.Certificate
	trustedCAPool := x509.NewCertPool()

	// Require Leaf as first cert in bundle
	if len(certBundle) > 0 {
		leaf = certBundle[0]
	} else {

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Ensure ca_file contains ONLY certificates in PEM format (BEGIN CERTIFICATE blocks)
  2. Split key material out of the file; keep the private key in the cert/key file, not the CA file
  3. Re-export the CA with `openssl x509 -in ca.crt -out ca.crt` to normalize the PEM block header

Example fix

// before
ocsp_ca_file: /etc/nats/server-key.pem  // contains PRIVATE KEY block
// after
ocsp_ca_file: /etc/nats/ca-bundle.pem   // only BEGIN CERTIFICATE blocks
Defensive patterns

Strategy: validation

Validate before calling

pemData, _ := os.ReadFile(caFile)
for rest := pemData; len(rest) > 0; {
    var b *pem.Block
    b, rest = pem.Decode(rest)
    if b == nil { break }
    if b.Type != "CERTIFICATE" { return fmt.Errorf("%s contains non-certificate PEM block %q", caFile, b.Type) }
}

Type guard

func isCertPEMType(b *pem.Block) bool { return b != nil && b.Type == "CERTIFICATE" }

Prevention

When it happens

Trigger: Calling getOCSPIssuer with a ca_file whose PEM contents include a block with block.Type != "CERTIFICATE"; parseCertPEM returns this error, which is then wrapped as "failed to parse ca_file".

Common situations: Pointing ocsp ca_file at a combined key+cert file (fullchain with private key), a CSR file, or a bundle containing a legacy 'X509 CERTIFICATE' typed block instead of the plain public CA cert PEM.

Understand the failure class

Related errors


AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02). Data as JSON: /api/errors/01736c51ada90627. Report an issue: GitHub.