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

  1. 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
  2. Verify cert_file and key_file paths exist and are readable by the agent user
  3. Ensure the key is an unencrypted PEM; decrypt or convert format if needed
  4. 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

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

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/166e736e56d0c138. Report an issue: GitHub.