hashicorp/nomad · critical

failed to parse CA file: %w

Error message

failed to parse CA file: %w

What it means

newTLSMetrics (used by the agent to report TLS certificate/CA expiry metrics) parses the configured CA file with caFileExpiry (x509 PEM parsing). If the CA file cannot be read or parsed as a valid PEM certificate, the error is wrapped with 'failed to parse CA file:'. Agent startup via NewAgent fails.

Source

Thrown at command/agent/tls_metrics.go:58

// newTLSMetrics creates a new tlsMetrics instance that can be used to
// periodically emit TLS certificate expiry metrics. It is the callers
// responsibility to ensure the passed TLS configuration is not-nil and valid.
//
// Once created, the start and stop methods can be used to control the
// background emission of metrics. The caller should create a new instance and
// stop the old instance each time TLS certificates are reloaded.
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

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Verify the path in tls.ca_file exists and is readable by the Nomad process user
  2. Confirm the file contains a PEM certificate block (-----BEGIN CERTIFICATE-----); use 'openssl x509 -in <file> -noout' to test
  3. Regenerate or re-fetch the CA bundle if corrupted or empty
  4. Check that the CA file is mounted/copied into containers before the agent starts
Defensive patterns

Strategy: validation

Validate before calling

pemBytes, err := os.ReadFile(caFile)
if err != nil { return err }
if block, _ := pem.Decode(pemBytes); block == nil || block.Type != "CERTIFICATE" {
    return fmt.Errorf("%s is not a PEM certificate", caFile)
}
if _, err := x509.ParseCertificate(block.Bytes); err != nil { return err }

Try / catch

exp, err := caFileExpiry(tlsCfg.CAFile)
if err != nil {
    return fmt.Errorf("failed to parse CA file %q: %w", tlsCfg.CAFile, err)
}

Prevention

When it happens

Trigger: tls { ca_file = "..." } pointing to a missing, unreadable, empty, or non-PEM file when the agent starts and newTLSMetrics is invoked.

Common situations: Wrong path in ca_file (typo, container path not mounted), CA file containing an intermediate-only or private-key PEM, file permissions blocking read, secret not yet rendered by a vault/template.

Understand the failure class

Related errors


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