nsqio/nsq · critical
failed to build client TLS config - %s
Error message
failed to build client TLS config - %s
What it means
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.
Source
Thrown at nsqd/nsqd.go:134
return nil, errors.New("--node-id must be [0,1024)")
}
if opts.TLSClientAuthPolicy != "" && opts.TLSRequired == TLSNotRequired {
opts.TLSRequired = TLSRequired
}
tlsConfig, err := buildTLSConfig(opts)
if err != nil {
return nil, fmt.Errorf("failed to build TLS config - %s", err)
}
if tlsConfig == nil && opts.TLSRequired != TLSNotRequired {
return nil, errors.New("cannot require TLS client connections without TLS key and cert")
}
n.tlsConfig = tlsConfig
clientTLSConfig, err := buildClientTLSConfig(opts)
if err != nil {
return nil, fmt.Errorf("failed to build client TLS config - %s", err)
}
n.clientTLSConfig = clientTLSConfig
if opts.AuthHTTPRequestMethod != "post" && opts.AuthHTTPRequestMethod != "get" {
return nil, errors.New("--auth-http-request-method must be post or get")
}
for _, v := range opts.E2EProcessingLatencyPercentiles {
if v <= 0 || v > 1 {
return nil, fmt.Errorf("invalid E2E processing latency percentile: %v", v)
}
}
n.logf(LOG_INFO, version.String("nsqd"))
n.logf(LOG_INFO, "ID: %d", opts.ID)
n.tcpServer = &tcpServer{nsqd: n}
n.tcpListener, err = net.Listen(util.TypeOfAddr(opts.TCPAddress), opts.TCPAddress)View on GitHub (pinned to 85cf10c09c)
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
Example fix
# before --tls-root-ca-file=/etc/nsqd/ca.der # DER, not PEM # after openssl x509 -inform DER -in /etc/nsqd/ca.der -out /etc/nsqd/ca.pem --tls-root-ca-file=/etc/nsqd/ca.pem
Defensive patterns
Strategy: validation
Validate before calling
b, err := os.ReadFile(caFile)
if err != nil { log.Fatalf("cannot read CA file: %v", err) }
if !x509.NewCertPool().AppendCertsFromPEM(b) {
log.Fatal("--tls-root-ca-file is not a PEM CA bundle")
} Try / catch
n, err := nsqd.New(opts)
if err != nil && strings.Contains(err.Error(), "failed to build client TLS config") {
// CA bundle unreadable/invalid: fix format or permissions, restart
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- failed to build TLS config - %s
- failed to append certificate to pool
- unknown tlsVersionOption %q
- cannot require TLS client connections without TLS key and ce
- cannot flock directory %s - %s (possibly in use by another i
AI-assisted analysis of nsqio/nsq@85cf10c09c (2026-08-16).
Data as JSON: /api/errors/92a18fe9167e3145.
Report an issue: GitHub.