{"record":{"id":"56b4ba9826ecab32","repo":"hashicorp/nomad","slug":"failed-to-parse-certificate","errorCode":null,"errorMessage":"failed to parse certificate","messagePattern":"failed to parse certificate","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"helper/tlsutil/generate.go","lineNumber":354,"sourceCode":"\t\t}\n\n\t\treturn pk, nil\n\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown PEM block type for signing key: %s\", block.Type)\n\t}\n}\n\nfunc Verify(caString, certString, dns string) error {\n\troots := x509.NewCertPool()\n\tok := roots.AppendCertsFromPEM([]byte(caString))\n\tif !ok {\n\t\treturn fmt.Errorf(\"failed to parse root certificate\")\n\t}\n\n\tcert, err := parseCert(certString)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse certificate\")\n\t}\n\n\topts := x509.VerifyOptions{\n\t\tDNSName: fmt.Sprint(dns),\n\t\tRoots:   roots,\n\t}\n\n\t_, err = cert.Verify(opts)\n\treturn err\n}\n","sourceCodeStart":336,"sourceCodeEnd":365,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/helper/tlsutil/generate.go#L336-L365","documentation":"After the CA pool is built, Verify parses the leaf certificate with parseCert; if that fails it wraps the failure as 'failed to parse certificate', meaning the leaf cert PEM is malformed or not a parseable x509 certificate.","triggerScenarios":"Calling tlsutil.Verify(ca, cert, dns) where certString fails x509 parsing (empty string, non-PEM bytes, truncated block, or unsupported format).","commonSituations":"Swapped config values so the CA ended up in the cert slot with valid parse but the cert slot holds a key or garbage; template/config rendering dropped part of the cert; DER-encoded cert instead of PEM.","solutions":["Confirm the cert argument is complete PEM starting with '-----BEGIN CERTIFICATE-----'","Run openssl x509 -in cert.pem -noout to check the certificate parses independently","Re-export the certificate from the CA in standard PEM encoding"],"exampleFix":"// before\nerr := tlsutil.Verify(caPEM, keyPEM, \"service.consul\")\n// after\nerr := tlsutil.Verify(caPEM, certPEM, \"service.consul\")","handlingStrategy":"validation","validationCode":"block, _ := pem.Decode([]byte(certString))\nif block == nil || block.Type != \"CERTIFICATE\" {\n\treturn errors.New(\"leaf cert missing or not PEM CERTIFICATE block\")\n}\nif _, err := x509.ParseCertificate(block.Bytes); err != nil {\n\treturn fmt.Errorf(\"leaf cert unparseable: %w\", err)\n}\nerr := tlsutil.Verify(caString, certString, dns)","typeGuard":"func isParseableCertificate(pemStr string) bool {\n\tblock, _ := pem.Decode([]byte(pemStr))\n\tif block == nil || block.Type != \"CERTIFICATE\" {\n\t\treturn false\n\t}\n\t_, err := x509.ParseCertificate(block.Bytes)\n\treturn err == nil\n}","tryCatchPattern":"if err := tlsutil.Verify(caPEM, certPEM, dns); err != nil {\n\tif err.Error() == \"failed to parse certificate\" {\n\t\treturn fmt.Errorf(\"leaf certificate unreadable — check cert config points at PEM cert: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Verify config key ordering: Verify(ca, cert, dns) — don't swap cert and key","Round-trip parse the cert with x509.ParseCertificate before use","Validate config file contents after template rendering","Store certs as complete PEM blocks with newlines preserved"],"tags":["tls","x509","certificate","pem"],"backgroundTag":"certificate-pem-parse-error","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"}