{"record":{"id":"96d5f1d8a38cd3dc","repo":"hashicorp/nomad","slug":"first-pem-block-should-be-certificate-type","errorCode":null,"errorMessage":"first PEM-block should be CERTIFICATE type","messagePattern":"first PEM-block should be CERTIFICATE type","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"helper/tlsutil/generate.go","lineNumber":292,"sourceCode":"\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// String formatted\n\tkID := sha256.Sum256(bs)\n\treturn kID[:], nil\n}\n\n// ParseCert parses the x509 certificate from a PEM-encoded value.\nfunc ParseCert(pemValue string) (*x509.Certificate, error) {\n\t// The _ result below is not an error but the remaining PEM bytes.\n\tblock, _ := pem.Decode([]byte(pemValue))\n\tif block == nil {\n\t\treturn nil, fmt.Errorf(\"no PEM-encoded data found\")\n\t}\n\n\tif block.Type != \"CERTIFICATE\" {\n\t\treturn nil, fmt.Errorf(\"first PEM-block should be CERTIFICATE type\")\n\t}\n\n\treturn x509.ParseCertificate(block.Bytes)\n}\n\nfunc parseCert(pemValue string) (*x509.Certificate, error) {\n\t// The _ result below is not an error but the remaining PEM bytes.\n\tblock, _ := pem.Decode([]byte(pemValue))\n\tif block == nil {\n\t\treturn nil, fmt.Errorf(\"no PEM-encoded data found\")\n\t}\n\n\tif block.Type != \"CERTIFICATE\" {\n\t\treturn nil, fmt.Errorf(\"first PEM-block should be CERTIFICATE type\")\n\t}\n\n\treturn x509.ParseCertificate(block.Bytes)\n}","sourceCodeStart":274,"sourceCodeEnd":310,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/helper/tlsutil/generate.go#L274-L310","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass the certificate (-----BEGIN CERTIFICATE-----) content, not the key or CSR.","If the PEM value is a combined bundle, split it and feed only the CERTIFICATE block to ParseCert (parseCert/ParseSigner handle the other halves).","Double-check config wiring so CertFile content goes to cert parsing and KeyFile content to ParseSigner.","If you have a CSR, get it signed (x509.CreateCertificate) before parsing."],"exampleFix":"// before\n_, err := tlsutil.ParseCert(keyPEM) // key passed by mistake\n// after\n_, err := tlsutil.ParseCert(certPEM)\n_, err = tlsutil.ParseSigner(keyPEM)","handlingStrategy":"type-guard","validationCode":"func firstBlockType(s string) string {\n\tblock, _ := pem.Decode([]byte(s))\n\tif block == nil { return \"\" }\n\treturn block.Type\n}","typeGuard":"func isCertificateBlock(s string) bool {\n\tblock, _ := pem.Decode([]byte(s))\n\treturn block != nil && (block.Type == \"CERTIFICATE\" || block.Type == \"X509 CERTIFICATE\")\n}","tryCatchPattern":"if got := firstBlockType(pemValue); got != \"CERTIFICATE\" {\n\treturn fmt.Errorf(\"expected CERTIFICATE block, got %q\", got)\n}\ncert, err := tlsutil.ParseCert(pemValue)\nif err != nil { return err }","preventionTips":["Keep cert and key PEM values in separate config fields; never concatenate them for cert parsing.","Check the BEGIN line of the first block before parsing.","Route keys to ParseSigner and certificates to ParseCert.","Verify provisioning pipelines store issued certs, not CSRs, in cert slots."],"tags":["tls","pem","certificate-parsing","wrong-input"],"backgroundTag":"wrong-pem-block-type","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}