rqlite/rqlite · critical
cannot create TLS config: %s
Error message
cannot create TLS config: %s
What it means
Returned by newTLSMux (via NewTLSMux / NewMutualTLSMux) when rtls.CreateServerConfigWithFunc fails to build the *tls.Config from the certificate reloader and CA settings. This happens after the cert reloader was created successfully, so the failure is in the CA certificate, mutual-TLS state, client-CN verification settings, or the generated config itself. Node-to-node TLS cannot be enabled without a valid config.
Source
Thrown at tcp/mux.go:154
}
mtlsState := rtls.MTLSStateDisabled
if mutual {
mtlsState = rtls.MTLSStateEnabled
}
mux.certReloader, err = rtls.NewCertReloader(cert, key)
if err != nil {
return nil, fmt.Errorf("cannot create cert monitor: %s", err)
}
// Wrap the GetCertificate function so we update the stats.
getCertFunc := func() (*tls.Certificate, error) {
stats.Add(numTLSCertFetched, 1)
return mux.certReloader.GetCertificate()
}
mux.tlsConfig, err = rtls.CreateServerConfigWithFunc(getCertFunc, caCert, mtlsState, verifyCN)
if err != nil {
return nil, fmt.Errorf("cannot create TLS config: %s", err)
}
mux.ln = tls.NewListener(ln, mux.tlsConfig)
return mux, nil
}
// Serve handles connections from ln and multiplexes then across registered listener.
func (mux *Mux) Serve() error {
tlsStr := ""
if mux.tlsConfig != nil {
tlsStr = "TLS "
}
mux.Logger.Printf("%smux serving on %s, advertising %s", tlsStr, mux.ln.Addr().String(), mux.addr)
for {
// Wait for the next connection.
// If it returns a temporary error then simply retry.
// If it returns any other error then exit immediately.View on GitHub (pinned to 7586a4d1bd)
Solutions
- Read the wrapped error; 'no such file' or 'failed to find any PEM data' means fix the CA path/content first.
- Validate the CA file: openssl x509 -in ca.pem -noout -text must parse and show a CA:TRUE basic constraint.
- Ensure the mutual-TLS flag combination matches the intent (client-cert required vs optional) per rqlite TLS docs.
- Restart the node after correcting the flags; confirm inter-node connectivity with the new config.
Example fix
// before rqlited -node-tls-cert c.pem -node-tls-key k.pem -node-tls-ca /etc/rqlite/missing-ca.pem // cannot create TLS config: open /etc/rqlite/missing-ca.pem: no such file or directory // after rqlited -node-tls-cert c.pem -node-tls-key k.pem -node-tls-ca /etc/rqlite/ca.pem
Defensive patterns
Strategy: validation
Validate before calling
caPEM, err := os.ReadFile(caCertPath)
if err != nil { return err }
pool := x509.NewCertPool()
if !pool.AppendCertsFromPEM(caPEM) { return errors.New("invalid or empty CA bundle") }
if !bytes.Contains(caPEM, []byte("BEGIN CERTIFICATE")) { return errors.New("CA file is not PEM") } Try / catch
mux, err := tcp.NewMutualTLSMux(ln, cert, key, caCert, verifyCN)
if err != nil && strings.Contains(err.Error(), "cannot create TLS config") {
log.Fatalf("invalid TLS/CA configuration: %v", err)
} Prevention
- Validate CA bundles with openssl x509 / x509 -CAfile before rollout.
- Ensure mTLS flags and CA files are provisioned together as one config unit.
- Confirm Kubernetes secrets include ca.crt and it is a valid PEM cert.
- Test mutual TLS between two nodes in staging before production rollout.
When it happens
Trigger: Starting rqlited with mutual TLS (-node-tls-ca / -node-verify-client / -node-no-verify-hostnames variants) where the CA cert file is missing, unreadable, or not a valid certificate; or invalid CA/mTLS-state combinations.
Common situations: CA bundle path typo; CA file empty or not PEM; combining -node-tls-ca with mismatched mutual-TLS flags; Kubernetes secret mounts missing the ca.crt key; expired root CA being rejected by strict parsing.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- failed to build TLS config: %w
- failed to create TLS config: %s
- cannot create cert monitor: %s
- -http-verify-common-name requires -http-verify-client
- -node-verify-common-name requires -node-verify-client
AI-assisted analysis of rqlite/rqlite@7586a4d1bd (2026-09-03).
Data as JSON: /api/errors/34b49c027b47c09a.
Report an issue: GitHub.