hashicorp/nomad · critical
failed to parse cert key pair: %w
Error message
failed to parse cert key pair: %w
What it means
newTLSMetrics loads the agent's TLS certificate and key via crypto/tls.LoadX509KeyPair. If the cert/key files are missing, malformed, mismatched, or encrypted, the error is wrapped as 'failed to parse cert key pair:' and agent startup fails.
Source
Thrown at command/agent/tls_metrics.go:66
func newTLSMetrics(logger hclog.Logger, tlsCfg *config.TLSConfig, labels []metrics.Label) (*tlsMetrics, error) {
t := tlsMetrics{
labels: labels,
logger: logger,
stopCh: make(chan struct{}),
}
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)View on GitHub (pinned to 482b49bf1a)
Solutions
- Test the pair with 'openssl x509 -noout -modulus -in cert.crt' and 'openssl rsa -noout -modulus -in key.pem' and compare moduli; reissue if mismatched
- Verify cert_file and key_file paths exist and are readable by the agent user
- Ensure the key is an unencrypted PEM; decrypt or convert format if needed
- Redeploy cert and key together from the same issuance
Defensive patterns
Strategy: validation
Validate before calling
if _, err := tls.LoadX509KeyPair(certFile, keyFile); err != nil {
return fmt.Errorf("cert/key pair invalid: %w", err)
} Try / catch
certs, err := tls.LoadX509KeyPair(tlsCfg.CertFile, tlsCfg.KeyFile)
if err != nil {
return fmt.Errorf("failed to parse cert key pair: %w", err)
} Prevention
- Deploy cert and key from the same issuance, atomically together
- Verify pair match by comparing 'openssl x509 -modulus' and 'openssl rsa -modulus' outputs
- Keep keys unencrypted and in PEM format
- Check file paths and permissions before agent startup
When it happens
Trigger: tls { cert_file, key_file } configured, and tls.LoadX509KeyPair fails at NewAgent time — bad paths, invalid PEM, key not matching certificate, or encrypted private key.
Common situations: Renewed certificate deployed without the matching key (or vice versa), wrong file paths, key in PKCS#8/encrypted format not accepted, whitespace/concatenation issues in combined PEM files.
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 bytes: %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/166e736e56d0c138.
Report an issue: GitHub.