hashicorp/nomad · error

first PEM-block should be CERTIFICATE type

Error message

first PEM-block should be CERTIFICATE type

What it means

The public ParseCert successfully decoded a PEM block, but its block.Type is not "CERTIFICATE" — the caller handed it a key, CSR, bundle starting with something else, or other PEM material. ParseCert only accepts a CERTIFICATE block as the first block.

Source

Thrown at helper/tlsutil/generate.go:292

	if err != nil {
		return nil, err
	}

	// String formatted
	kID := sha256.Sum256(bs)
	return kID[:], nil
}

// ParseCert parses the x509 certificate from a PEM-encoded value.
func ParseCert(pemValue string) (*x509.Certificate, error) {
	// The _ result below is not an error but the remaining PEM bytes.
	block, _ := pem.Decode([]byte(pemValue))
	if block == nil {
		return nil, fmt.Errorf("no PEM-encoded data found")
	}

	if block.Type != "CERTIFICATE" {
		return nil, fmt.Errorf("first PEM-block should be CERTIFICATE type")
	}

	return x509.ParseCertificate(block.Bytes)
}

func parseCert(pemValue string) (*x509.Certificate, error) {
	// The _ result below is not an error but the remaining PEM bytes.
	block, _ := pem.Decode([]byte(pemValue))
	if block == nil {
		return nil, fmt.Errorf("no PEM-encoded data found")
	}

	if block.Type != "CERTIFICATE" {
		return nil, fmt.Errorf("first PEM-block should be CERTIFICATE type")
	}

	return x509.ParseCertificate(block.Bytes)
}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Pass the certificate (-----BEGIN CERTIFICATE-----) content, not the key or CSR.
  2. If the PEM value is a combined bundle, split it and feed only the CERTIFICATE block to ParseCert (parseCert/ParseSigner handle the other halves).
  3. Double-check config wiring so CertFile content goes to cert parsing and KeyFile content to ParseSigner.
  4. If you have a CSR, get it signed (x509.CreateCertificate) before parsing.

Example fix

// before
_, err := tlsutil.ParseCert(keyPEM) // key passed by mistake
// after
_, err := tlsutil.ParseCert(certPEM)
_, err = tlsutil.ParseSigner(keyPEM)
Defensive patterns

Strategy: type-guard

Validate before calling

func firstBlockType(s string) string {
	block, _ := pem.Decode([]byte(s))
	if block == nil { return "" }
	return block.Type
}

Type guard

func isCertificateBlock(s string) bool {
	block, _ := pem.Decode([]byte(s))
	return block != nil && (block.Type == "CERTIFICATE" || block.Type == "X509 CERTIFICATE")
}

Try / catch

if got := firstBlockType(pemValue); got != "CERTIFICATE" {
	return fmt.Errorf("expected CERTIFICATE block, got %q", got)
}
cert, err := tlsutil.ParseCert(pemValue)
if err != nil { return err }

Prevention

When it happens

Trigger: Calling ParseCert on a PEM private key (EC PRIVATE KEY / RSA PRIVATE KEY / PRIVATE KEY), a CSR (CERTIFICATE REQUEST), a CRL, or a cert chain where a key block precedes the certificate.

Common situations: Swapping cert and key config fields; concatenating key+cert into one value and passing it to ParseCert; using a CSR where a certificate is expected; clients submitting a certificate-signing request instead of the issued cert.

Understand the failure class

Related errors


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