{"record":{"id":"92a18fe9167e3145","repo":"nsqio/nsq","slug":"failed-to-build-client-tls-config-s","errorCode":null,"errorMessage":"failed to build client TLS config - %s","messagePattern":"failed to build client TLS config - (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"nsqd/nsqd.go","lineNumber":134,"sourceCode":"\t\treturn nil, errors.New(\"--node-id must be [0,1024)\")\n\t}\n\n\tif opts.TLSClientAuthPolicy != \"\" && opts.TLSRequired == TLSNotRequired {\n\t\topts.TLSRequired = TLSRequired\n\t}\n\n\ttlsConfig, err := buildTLSConfig(opts)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to build TLS config - %s\", err)\n\t}\n\tif tlsConfig == nil && opts.TLSRequired != TLSNotRequired {\n\t\treturn nil, errors.New(\"cannot require TLS client connections without TLS key and cert\")\n\t}\n\tn.tlsConfig = tlsConfig\n\n\tclientTLSConfig, err := buildClientTLSConfig(opts)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to build client TLS config - %s\", err)\n\t}\n\tn.clientTLSConfig = clientTLSConfig\n\n\tif opts.AuthHTTPRequestMethod != \"post\" && opts.AuthHTTPRequestMethod != \"get\" {\n\t\treturn nil, errors.New(\"--auth-http-request-method must be post or get\")\n\t}\n\n\tfor _, v := range opts.E2EProcessingLatencyPercentiles {\n\t\tif v <= 0 || v > 1 {\n\t\t\treturn nil, fmt.Errorf(\"invalid E2E processing latency percentile: %v\", v)\n\t\t}\n\t}\n\n\tn.logf(LOG_INFO, version.String(\"nsqd\"))\n\tn.logf(LOG_INFO, \"ID: %d\", opts.ID)\n\n\tn.tcpServer = &tcpServer{nsqd: n}\n\tn.tcpListener, err = net.Listen(util.TypeOfAddr(opts.TCPAddress), opts.TCPAddress)","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/nsqio/nsq/blob/85cf10c09c6c3c86160d6f0eb156f62d0efc1648/nsqd/nsqd.go#L116-L152","documentation":"Separately from the server config, nsqd.New builds a client TLS config used for its own outbound TLS connections (e.g. to nsqlookupd). buildClientTLSConfig only touches --tls-root-ca-file: it reads the file and must parse it as PEM into the root pool ('failed to append certificate to pool' otherwise). Unreadable or non-PEM files produce this wrapped error.","triggerScenarios":"Setting --tls-root-ca-file to a path that does not exist or that the nsqd user cannot read; pointing it at a DER-encoded or otherwise non-PEM CA file; a truncated file after a config-management push.","commonSituations":"Self-signed lookupd PKI where the CA was exported in DER format; file permissions 0600 root:root in a container running as nobody; volume mounts that materialize the file late or empty.","solutions":["Confirm the file exists and is readable by the nsqd user","Convert DER to PEM if needed: openssl x509 -inform DER -in ca.der -out ca.pem","Validate it parses: openssl x509 -in ca.pem -noout","Point --tls-root-ca-file at the PEM CA bundle that signed your lookupd certificates"],"exampleFix":"# before\n--tls-root-ca-file=/etc/nsqd/ca.der   # DER, not PEM\n\n# after\nopenssl x509 -inform DER -in /etc/nsqd/ca.der -out /etc/nsqd/ca.pem\n--tls-root-ca-file=/etc/nsqd/ca.pem","handlingStrategy":"validation","validationCode":"b, err := os.ReadFile(caFile)\nif err != nil { log.Fatalf(\"cannot read CA file: %v\", err) }\nif !x509.NewCertPool().AppendCertsFromPEM(b) {\n\tlog.Fatal(\"--tls-root-ca-file is not a PEM CA bundle\")\n}","typeGuard":null,"tryCatchPattern":"n, err := nsqd.New(opts)\nif err != nil && strings.Contains(err.Error(), \"failed to build client TLS config\") {\n\t// CA bundle unreadable/invalid: fix format or permissions, restart\n}","preventionTips":["Distribute CAs as PEM bundles, converting DER once at packaging time","Verify readability as the nsqd service user in config management","Pair the CA file with the same rotation pipeline as the server certificates"],"tags":["nsqd","tls","ca","certificates","startup"],"backgroundTag":null,"analyzedSha":"85cf10c09c6c3c86160d6f0eb156f62d0efc1648","analyzedAt":"2026-08-16T00:53:05.009Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}