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
- Ensure ca_file contains ONLY certificates in PEM format (BEGIN CERTIFICATE blocks)
- Split key material out of the file; keep the private key in the cert/key file, not the CA file
- 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
- Keep CA trust files separate from private key files
- Validate PEM files with openssl before deploying
- Use only BEGIN CERTIFICATE blocks in ca_file
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
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- failed to parse ca_file: %v
- failed to parse cert: %v
- invalid chain link
- no available OCSP servers
- unable to plug TLS verify connection, config is nil
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/01736c51ada90627.
Report an issue: GitHub.