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. It

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Verify the certificate with 'openssl x509 -in cert.pem -text -noout'; reissue/redownload if it fails
  2. Ensure the first PEM block in cert_file is the leaf certificate
  3. Regenerate the certificate from the CA if bytes are truncated or corrupted
  4. 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

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

Related errors


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