hashicorp/nomad · critical
failed to parse cert bytes: %w
Error message
failed to parse cert bytes: %w
What it means
After LoadX509KeyPair succeeds, newTLSMetrics parses the first DER-encoded certificate with x509.ParseCertificate to read its NotAfter expiry. Failure means the leaf certificate bytes are structurally invalid (corrupt or non-standard encoding), so startup is aborted with 'failed to parse cert bytes:'.
Source
Thrown at command/agent/tls_metrics.go:72
}
exp, err := caFileExpiry(tlsCfg.CAFile)
if err != nil {
return nil, fmt.Errorf("failed to parse CA file: %w", err)
}
t.caExpiry = exp
// Using LoadX509KeyPair helps with parsing files with combined
// public/private keys, whitespace, etc.
certs, err := tls.LoadX509KeyPair(tlsCfg.CertFile, tlsCfg.KeyFile)
if err != nil {
return nil, fmt.Errorf("failed to parse cert key pair: %w", err)
}
// we are guaranteed to have at least 1 cert if LoadX509 succeeds
c, err := x509.ParseCertificate(certs.Certificate[0])
if err != nil {
return nil, fmt.Errorf("failed to parse cert bytes: %w", err)
}
t.certExpiry = c.NotAfter
return &t, nil
}
// start launches the background goroutine that emits TLS certificate expiry
// metrics at regular intervals. The interval is defined by the caller and
// should be based on the agents telemetry configuration.
func (t *tlsMetrics) start(interval time.Duration) {
t.logger.Info("starting TLS expiration metric process")
go t.emitLoop(interval)
}
// stop signals the background goroutine to stop emitting metrics.
func (t *tlsMetrics) stop() { close(t.stopCh) }
// emitLoop periodically emits TLS certificate expiry metrics until stopped. ItView on GitHub (pinned to 482b49bf1a)
Solutions
- Verify the certificate with 'openssl x509 -in cert.pem -text -noout'; reissue/redownload if it fails
- Ensure the first PEM block in cert_file is the leaf certificate
- Regenerate the certificate from the CA if bytes are truncated or corrupted
- Check that secret-rendering tooling (vault-agent, consul-template) completed before agent start
Defensive patterns
Strategy: validation
Validate before calling
der, _ := pem.Decode(certPEM)
if der == nil || der.Type != "CERTIFICATE" { return errors.New("no certificate PEM block") }
if _, err := x509.ParseCertificate(der.Bytes); err != nil { return err } Try / catch
c, err := x509.ParseCertificate(certs.Certificate[0])
if err != nil {
return fmt.Errorf("failed to parse cert bytes: %w", err)
} Prevention
- Verify certs with 'openssl x509 -text -noout' before deployment
- Ensure the leaf certificate is the first block in cert_file
- Check file integrity (size/checksum) after transfer or secret rendering
- Reissue certificates that fail openssl parsing rather than debugging DER bytes
When it happens
Trigger: tls.LoadX509KeyPair returns a chain whose first element cannot be parsed by x509.ParseCertificate — typically corrupt/truncated DER bytes or a non-certificate entry first in the combined file.
Common situations: Corrupted cert file from a failed download/secret render, a file where the first PEM block is not a certificate, unusual encodings produced by custom tooling.
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
- failed to parse cert key pair: %w
- invalid certificate: %s not in expected %s
- failed to parse CA file: %w
- failed to parse root certificate
- failed to parse certificate
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/bf77fd6442af22ab.
Report an issue: GitHub.