hashicorp/nomad · error

no PEM-encoded data found

Error message

no PEM-encoded data found

What it means

caFileExpiry in command/agent/tls_metrics.go reads a CA certificate file for TLS expiry metrics and decodes the first PEM block. If pem.Decode finds no PEM data (block == nil), it returns this error, meaning the file is not PEM-encoded (or is empty/garbage) and certificate expiry cannot be computed.

Source

Thrown at command/agent/tls_metrics.go:144

		metrics.SetGaugeWithLabels(
			[]string{"agent", "tls", "ca", "expiration_seconds"},
			float32(time.Until(t.caExpiry).Seconds()),
			t.labels,
		)
	}
}

// certFileExpiry reads a PEM-encoded certificate file and returns the NotAfter
// time of the certificate.
func caFileExpiry(path string) (time.Time, error) {
	data, err := os.ReadFile(path)
	if err != nil {
		return time.Time{}, fmt.Errorf("failed to read file: %w", err)
	}

	block, _ := pem.Decode(data)
	if block == nil {
		return time.Time{}, errors.New("no PEM-encoded data found")
	}

	cert, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		return time.Time{}, fmt.Errorf("failed to parse certificate: %w", err)
	}

	return cert.NotAfter, nil
}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Ensure the file contains a PEM-encoded certificate: it should start with `-----BEGIN CERTIFICATE-----`; convert DER to PEM with `openssl x509 -inform der -in ca.crt -out ca.pem`.
  2. Verify the file path in the agent TLS config points to the CA cert, not the key, directory, or an unrelated file.
  3. Check the file is non-empty and intact (`openssl x509 -in ca.pem -noout -subject`) and re-copy if corrupted.
  4. Confirm file permissions allow the Nomad agent user to read the file (though unreadable files usually surface as the read error instead).

Example fix

// before: DER binary cert
ca_file = "/etc/ssl/ca.crt"   // DER-encoded
// after: convert to PEM
// openssl x509 -inform der -in /etc/ssl/ca.crt -out /etc/ssl/ca.pem
ca_file = "/etc/ssl/ca.pem"
Defensive patterns

Strategy: validation

Validate before calling

data, err := os.ReadFile(caFile)
if err != nil {
    return err
}
if block, _ := pem.Decode(data); block == nil {
    return fmt.Errorf("%s is not PEM-encoded; convert with: openssl x509 -inform der -in %s -out ca.pem", caFile, caFile)
}

Type guard

func isPEMCertificate(data []byte) bool {
    block, _ := pem.Decode(data)
    return block != nil && block.Type == "CERTIFICATE"
}

Try / catch

if _, err := tls.LoadX509KeyPair(certFile, keyFile); err != nil {
    log.Printf("TLS files invalid: %v", err)
}
// at runtime:
if err != nil && strings.Contains(err.Error(), "no PEM-encoded data found") {
    return fmt.Errorf("check ca_file %q: file is not PEM (DER or corrupt?)", caFile)
}

Prevention

When it happens

Trigger: Configuring the agent's TLS CA file path (caFile) to a file that contains DER binary, an empty file, a private key format pem.Decode rejects, or plain text — then TLS metrics initialization (newTLSMetrics) invokes caFileExpiry.

Common situations: Pointing ca_file at a DER-encoded .crt (common from some CAs), at a directory or socket, at a bundle with only non-certificate PEM that pem.Decode can't parse, or a file truncated by a failed copy/download.

Related errors


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