{"record":{"id":"bf77fd6442af22ab","repo":"hashicorp/nomad","slug":"failed-to-parse-cert-bytes-w","errorCode":null,"errorMessage":"failed to parse cert bytes: %w","messagePattern":"failed to parse cert bytes: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"command/agent/tls_metrics.go","lineNumber":72,"sourceCode":"\t}\n\n\texp, err := caFileExpiry(tlsCfg.CAFile)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse CA file: %w\", err)\n\t}\n\tt.caExpiry = exp\n\n\t// Using LoadX509KeyPair helps with parsing files with combined\n\t// public/private keys, whitespace, etc.\n\tcerts, err := tls.LoadX509KeyPair(tlsCfg.CertFile, tlsCfg.KeyFile)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse cert key pair: %w\", err)\n\t}\n\n\t// we are guaranteed to have at least 1 cert if LoadX509 succeeds\n\tc, err := x509.ParseCertificate(certs.Certificate[0])\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse cert bytes: %w\", err)\n\t}\n\tt.certExpiry = c.NotAfter\n\n\treturn &t, nil\n}\n\n// start launches the background goroutine that emits TLS certificate expiry\n// metrics at regular intervals. The interval is defined by the caller and\n// should be based on the agents telemetry configuration.\nfunc (t *tlsMetrics) start(interval time.Duration) {\n\tt.logger.Info(\"starting TLS expiration metric process\")\n\tgo t.emitLoop(interval)\n}\n\n// stop signals the background goroutine to stop emitting metrics.\nfunc (t *tlsMetrics) stop() { close(t.stopCh) }\n\n// emitLoop periodically emits TLS certificate expiry metrics until stopped. It","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/command/agent/tls_metrics.go#L54-L90","documentation":"After LoadX509KeyPair succeeds, newTLSMetrics parses the first DER-encoded certificate with x509.ParseCertificate to read its NotAfter expiry. Failure means the leaf certificate bytes are structurally invalid (corrupt or non-standard encoding), so startup is aborted with 'failed to parse cert bytes:'.","triggerScenarios":"tls.LoadX509KeyPair returns a chain whose first element cannot be parsed by x509.ParseCertificate — typically corrupt/truncated DER bytes or a non-certificate entry first in the combined file.","commonSituations":"Corrupted cert file from a failed download/secret render, a file where the first PEM block is not a certificate, unusual encodings produced by custom tooling.","solutions":["Verify the certificate with 'openssl x509 -in cert.pem -text -noout'; reissue/redownload if it fails","Ensure the first PEM block in cert_file is the leaf certificate","Regenerate the certificate from the CA if bytes are truncated or corrupted","Check that secret-rendering tooling (vault-agent, consul-template) completed before agent start"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"der, _ := pem.Decode(certPEM)\nif der == nil || der.Type != \"CERTIFICATE\" { return errors.New(\"no certificate PEM block\") }\nif _, err := x509.ParseCertificate(der.Bytes); err != nil { return err }","typeGuard":null,"tryCatchPattern":"c, err := x509.ParseCertificate(certs.Certificate[0])\nif err != nil {\n    return fmt.Errorf(\"failed to parse cert bytes: %w\", err)\n}","preventionTips":["Verify certs with 'openssl x509 -text -noout' before deployment","Ensure the leaf certificate is the first block in cert_file","Check file integrity (size/checksum) after transfer or secret rendering","Reissue certificates that fail openssl parsing rather than debugging DER bytes"],"tags":["tls","x509","certificate","nomad"],"backgroundTag":"tls-certificate-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"}