{"record":{"id":"43963e22fc68f09f","repo":"hashicorp/nomad","slug":"failed-to-parse-ca-file-w","errorCode":null,"errorMessage":"failed to parse CA file: %w","messagePattern":"failed to parse CA file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"command/agent/tls_metrics.go","lineNumber":58,"sourceCode":"\n// newTLSMetrics creates a new tlsMetrics instance that can be used to\n// periodically emit TLS certificate expiry metrics. It is the callers\n// responsibility to ensure the passed TLS configuration is not-nil and valid.\n//\n// Once created, the start and stop methods can be used to control the\n// background emission of metrics. The caller should create a new instance and\n// stop the old instance each time TLS certificates are reloaded.\nfunc newTLSMetrics(logger hclog.Logger, tlsCfg *config.TLSConfig, labels []metrics.Label) (*tlsMetrics, error) {\n\n\tt := tlsMetrics{\n\t\tlabels: labels,\n\t\tlogger: logger,\n\t\tstopCh: make(chan struct{}),\n\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","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/command/agent/tls_metrics.go#L40-L76","documentation":"newTLSMetrics (used by the agent to report TLS certificate/CA expiry metrics) parses the configured CA file with caFileExpiry (x509 PEM parsing). If the CA file cannot be read or parsed as a valid PEM certificate, the error is wrapped with 'failed to parse CA file:'. Agent startup via NewAgent fails.","triggerScenarios":"tls { ca_file = \"...\" } pointing to a missing, unreadable, empty, or non-PEM file when the agent starts and newTLSMetrics is invoked.","commonSituations":"Wrong path in ca_file (typo, container path not mounted), CA file containing an intermediate-only or private-key PEM, file permissions blocking read, secret not yet rendered by a vault/template.","solutions":["Verify the path in tls.ca_file exists and is readable by the Nomad process user","Confirm the file contains a PEM certificate block (-----BEGIN CERTIFICATE-----); use 'openssl x509 -in <file> -noout' to test","Regenerate or re-fetch the CA bundle if corrupted or empty","Check that the CA file is mounted/copied into containers before the agent starts"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"pemBytes, err := os.ReadFile(caFile)\nif err != nil { return err }\nif block, _ := pem.Decode(pemBytes); block == nil || block.Type != \"CERTIFICATE\" {\n    return fmt.Errorf(\"%s is not a PEM certificate\", caFile)\n}\nif _, err := x509.ParseCertificate(block.Bytes); err != nil { return err }","typeGuard":null,"tryCatchPattern":"exp, err := caFileExpiry(tlsCfg.CAFile)\nif err != nil {\n    return fmt.Errorf(\"failed to parse CA file %q: %w\", tlsCfg.CAFile, err)\n}","preventionTips":["Test CA files with 'openssl x509 -in <file> -noout' before deploying","Ensure the file is mounted and readable by the agent user before startup","Deploy CA bundles atomically (write temp file, rename)","Verify secret-rendering tools finished before agent start"],"tags":["tls","x509","file-parsing","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"}