hashicorp/nomad · error

unknown PEM block type for signing key: %s

Error message

unknown PEM block type for signing key: %s

What it means

ParseSigner parses a PEM-encoded private key and returns a crypto.Signer. It supports RSA, EC, and PKCS#8 (Ed25519) PEM blocks; any other PEM block type reaches the default branch and this error is thrown, carrying the unrecognized block.Type header.

Source

Thrown at helper/tlsutil/generate.go:341

		return x509.ParseECPrivateKey(block.Bytes)

	case "RSA PRIVATE KEY":
		return x509.ParsePKCS1PrivateKey(block.Bytes)

	case "PRIVATE KEY":
		signer, err := x509.ParsePKCS8PrivateKey(block.Bytes)
		if err != nil {
			return nil, err
		}
		pk, ok := signer.(crypto.Signer)
		if !ok {
			return nil, fmt.Errorf("private key is not a valid format")
		}

		return pk, nil

	default:
		return nil, fmt.Errorf("unknown PEM block type for signing key: %s", block.Type)
	}
}

func Verify(caString, certString, dns string) error {
	roots := x509.NewCertPool()
	ok := roots.AppendCertsFromPEM([]byte(caString))
	if !ok {
		return fmt.Errorf("failed to parse root certificate")
	}

	cert, err := parseCert(certString)
	if err != nil {
		return fmt.Errorf("failed to parse certificate")
	}

	opts := x509.VerifyOptions{
		DNSName: fmt.Sprint(dns),
		Roots:   roots,

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Inspect block.Type with pem.Decode on the file and confirm it contains the intended private key, not the certificate
  2. Regenerate or export the key as PKCS#8 ('BEGIN PRIVATE KEY') or the matching RSA/EC private-key PEM format
  3. If the file holds a cert+key bundle, split out only the private-key section before parsing

Example fix

// before
signer, err := tlsutil.ParseSigner(certPEM) // cert block, not key
// after
signer, err := tlsutil.ParseSigner(keyPEM) // block type: RSA/EC PRIVATE KEY or PRIVATE KEY
Defensive patterns

Strategy: validation

Validate before calling

block, _ := pem.Decode(keyPEM)
if block == nil {
	return fmt.Errorf("no PEM data found")
}
switch block.Type {
case "RSA PRIVATE KEY", "EC PRIVATE KEY", "PRIVATE KEY":
	// ok
default:
	return fmt.Errorf("unsupported key block type %q", block.Type)
}
signer, err := tlsutil.ParseSigner(keyPEM)

Type guard

func isPrivateKeyPEM(pemBytes []byte) bool {
	block, _ := pem.Decode(pemBytes)
	return block != nil && (block.Type == "RSA PRIVATE KEY" || block.Type == "EC PRIVATE KEY" || block.Type == "PRIVATE KEY")
}

Try / catch

signer, err := tlsutil.ParseSigner(keyPEM)
if err != nil {
	if strings.HasPrefix(err.Error(), "unknown PEM block type") {
		return fmt.Errorf("key file is not a supported private key PEM (check cert vs key): %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: Calling ParseSigner (directly or via newCert/Run/IsValidSigner in tlsutil) with PEM data whose block type is not 'RSA PRIVATE KEY', 'EC PRIVATE KEY', or 'PRIVATE KEY' — e.g. a public key, certificate, or encrypted key block passed where a private key is expected.

Common situations: Pointing a CA/leaf key config at the certificate file instead of the key file; passing an encrypted 'ENCRYPTED PRIVATE KEY' or legacy format; concatenating cert+key in one file and feeding the whole bundle to ParseSigner.

Related errors


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