{"record":{"id":"0e7c72eec1e2da60","repo":"nsqio/nsq","slug":"failed-to-append-certificate-to-pool","errorCode":null,"errorMessage":"failed to append certificate to pool","messagePattern":"failed to append certificate to pool","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nsqd/nsqd.go","lineNumber":776,"sourceCode":"\t\ttlsClientAuthPolicy = tls.RequireAnyClientCert\n\tcase \"require-verify\":\n\t\ttlsClientAuthPolicy = tls.RequireAndVerifyClientCert\n\t}\n\n\ttlsConfig = &tls.Config{\n\t\tCertificates: []tls.Certificate{cert},\n\t\tClientAuth:   tlsClientAuthPolicy,\n\t\tMinVersion:   opts.TLSMinVersion,\n\t}\n\n\tif opts.TLSRootCAFile != \"\" {\n\t\ttlsCertPool := x509.NewCertPool()\n\t\tcaCertFile, err := os.ReadFile(opts.TLSRootCAFile)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif !tlsCertPool.AppendCertsFromPEM(caCertFile) {\n\t\t\treturn nil, errors.New(\"failed to append certificate to pool\")\n\t\t}\n\t\ttlsConfig.ClientCAs = tlsCertPool\n\t}\n\n\treturn tlsConfig, nil\n}\n\nfunc buildClientTLSConfig(opts *Options) (*tls.Config, error) {\n\ttlsConfig := &tls.Config{\n\t\tMinVersion: opts.TLSMinVersion,\n\t}\n\n\tif opts.TLSRootCAFile != \"\" {\n\t\ttlsCertPool := x509.NewCertPool()\n\t\tcaCertFile, err := os.ReadFile(opts.TLSRootCAFile)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}","sourceCodeStart":758,"sourceCodeEnd":794,"githubUrl":"https://github.com/nsqio/nsq/blob/85cf10c09c6c3c86160d6f0eb156f62d0efc1648/nsqd/nsqd.go#L758-L794","documentation":"nsqd builds its server-side TLS config in buildTLSConfig (nsqd/nsqd.go). When --tls-root-ca-file is set, it reads the file and calls x509.CertPool.AppendCertsFromPEM to seed ClientCAs, which is used to verify client certificates when --tls-client-auth-policy requires or requests client certs. AppendCertsFromPEM returns false (no error value) when the file contains no parseable CERTIFICATE PEM blocks, so nsqd cannot build the pool and startup aborts. The file was read successfully; only its contents are wrong.","triggerScenarios":"Starting nsqd with --tls-root-ca-file pointing at a file whose contents are not PEM CERTIFICATE blocks: a DER/binary CA cert, a PEM with only PRIVATE KEY or CSR blocks, an empty or truncated file, or a file with mangled BEGIN/END lines or Windows line-corruption.","commonSituations":"Ops copies the server key/cert instead of the CA cert into the path; a cert downloaded from an internal CA arrives as DER (.crt binary) while Go only accepts PEM; concatenating files and losing the footer line '-----END CERTIFICATE-----'; passing the fullchain in a format produced by a different tool.","solutions":["Verify the file actually contains PEM certificates: 'openssl x509 -in /path/ca.pem -noout -subject' (for DER use 'openssl x509 -inform der -in ca.der -out ca.pem' to convert).","Check you referenced the CA certificate, not the server key/cert or a CSR, in --tls-root-ca-file.","If the file is a bundle, confirm each block parses: 'grep -c \"BEGIN CERTIFICATE\" ca.pem' should be >= 1 and openssl should read every block.","Re-run nsqd; startup now proceeds past TLS config."],"exampleFix":"# before (DER file or wrong file)\nnsqd --tls-root-ca-file=/etc/nsq/ca.crt   # ca.crt is DER-encoded -> AppendCertsFromPEM fails\n\n# after\nopenssl x509 -inform der -in /etc/nsq/ca.der -out /etc/nsq/ca.pem\nnsqd --tls-root-ca-file=/etc/nsq/ca.pem","handlingStrategy":"validation","validationCode":"// pre-flight: ensure the CA file nsqd will load parses as PEM certificates\nfunc validPEMCAs(path string) bool {\n    data, err := os.ReadFile(path)\n    if err != nil {\n        return false\n    }\n    return x509.NewCertPool().AppendCertsFromPEM(data)\n}\n\nif !validPEMCAs(opts.TLSRootCAFile) {\n    return fmt.Errorf(\"%s is not a PEM CA bundle; convert DER or fix the file\", opts.TLSRootCAFile)\n}","typeGuard":null,"tryCatchPattern":"// in process supervisors / test harnesses around nsqd startup\nif err := nsqd.New(opts); err != nil {\n    if strings.Contains(err.Error(), \"failed to append certificate to pool\") {\n        log.Printf(\"TLS CA file %s is not valid PEM — regenerate/convert it\", opts.TLSRootCAFile)\n    }\n    return err\n}","preventionTips":["Keep CA files in PEM (not DER) in your config management from the start.","Add a CI step that runs AppendCertsFromPEM on every shipped TLS file before deploy.","Name files explicitly (ca.pem, server-key.pem) so the wrong artifact is never wired into --tls-root-ca-file."],"tags":["tls","x509","pem","configuration","startup","nsqd"],"backgroundTag":null,"analyzedSha":"85cf10c09c6c3c86160d6f0eb156f62d0efc1648","analyzedAt":"2026-08-16T00:53:05.009Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}