hashicorp/nomad · error
failed to decode %s PEM block
Error message
failed to decode %s PEM block
What it means
getCassCert read the cert bytes but pem.Decode found no valid PEM block — the data lacks recognizable BEGIN/END certificate markers or the base64 body is invalid. newlineHeaders fixes surrounding newlines, so the content itself is not valid PEM.
Source
Thrown at lib/auth/oidc/client_assertion.go:176
if k.PemCertFile != "" {
source = "PemCertFile"
bts, err = os.ReadFile(k.PemCertFile)
if err != nil {
return nil, fmt.Errorf("error reading %s: %w", source, err)
}
}
// or pem string
if k.PemCert != "" {
source = "PemCert"
bts = []byte(k.PemCert)
}
// ensure newlines around pem header/footer
bts = newlineHeaders(bts)
block, _ := pem.Decode(bts)
if block == nil {
return nil, fmt.Errorf("failed to decode %s PEM block", source)
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, fmt.Errorf("failed to parse %s bytes: %w", source, err)
}
now := time.Now()
if now.Before(cert.NotBefore) || now.After(cert.NotAfter) {
return nil, errors.New("certificate has expired or is not yet valid")
}
return cert, nil
}
// hashKeyID derives a "certificate thumbprint" that the OIDC provider uses
// to find the certificate to verify the private key JWT signature.
// https://datatracker.ietf.org/doc/html/rfc7515#section-4.1.7
func hashKeyID(cert *x509.Certificate, header structs.OIDCClientAssertionKeyIDHeader) (string, error) {
var hasher hash.Hash
switch header {View on GitHub (pinned to 482b49bf1a)
Solutions
- Verify the content starts with `-----BEGIN CERTIFICATE-----` and ends with `-----END CERTIFICATE-----`; re-export with `openssl x509 -in cert.crt -out cert.pem`.
- If the value is base64, decode it first: `base64 -d cert.b64 > cert.pem`.
- Check the file is non-empty and contains the certificate, not the private key or an error page.
Example fix
// before: base64 blob pasted as PemCert PemCert: "LS0tLS1CRUdJTi..." // after: decoded PEM PemCert: "-----BEGIN CERTIFICATE-----\nMIID...\n-----END CERTIFICATE-----"
Defensive patterns
Strategy: validation
Validate before calling
func validateCertPEM(s string) error {
blk, _ := pem.Decode([]byte(s))
if blk == nil || blk.Type != "CERTIFICATE" {
return fmt.Errorf("value is not a PEM certificate")
}
_, err := x509.ParseCertificate(blk.Bytes)
return err
} Type guard
func isPEMCertificate(s string) bool {
blk, _ := pem.Decode([]byte(s))
return blk != nil && blk.Type == "CERTIFICATE"
} Try / catch
key, err := getCassCert(k)
if err != nil && strings.Contains(err.Error(), "failed to decode") {
return fmt.Errorf("cert value is not PEM; decode base64 or re-export via openssl x509: %w", err)
} Prevention
- Decode base64-wrapped secrets before storing them in PemCert/PemCertFile.
- Verify files begin with `-----BEGIN CERTIFICATE-----` after templating.
- Validate with `openssl x509 -in cert.pem -noout` before configuring.
When it happens
Trigger: BuildClientAssertionJWT → getCassCert after reading PemCertFile/PemCert, when the bytes are not a PEM certificate (raw DER, JSON-wrapped secret, empty file, HTML error page).
Common situations: Secret store returned the cert base64-encoded and it was pasted without decoding; file contains the key instead of the cert; templating stripped the PEM headers; empty placeholder file.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- error parsing %s: %w
- failed to parse %s bytes: %w
- no PEM-encoded data found
- require only one of PemKey or PemKeyFile
- missing PemCert, PemCertFile, or KeyID
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/2ed6665eee855de7.
Report an issue: GitHub.