temporalio/temporal · critical
failed to fetch client CAs: %v
Error message
failed to fetch client CAs: %v
What it means
When mutual TLS is enabled (requireClientAuth), the server fetches the CA pool used to verify client certificates via certProvider.FetchClientCAs(). Any failure is wrapped as "failed to fetch client CAs: %v". This blocks construction of the server TLS config, since client certificate verification requires a trust pool.
Source
Thrown at common/rpc/encryption/local_store_tls_provider.go:351
return nil, fmt.Errorf("loading server tls certificate failed: %v", err)
}
// tls disabled, responsibility of cert provider above to error otherwise
if serverCert == nil {
return nil, nil
}
// Default to NoClientAuth
clientAuthType := tls.NoClientCert
var clientCaPool *x509.CertPool
// If mTLS enabled
if requireClientAuth {
clientAuthType = tls.RequireAndVerifyClientCert
ca, err := certProvider.FetchClientCAs()
if err != nil {
return nil, fmt.Errorf("failed to fetch client CAs: %v", err)
}
clientCaPool = ca
}
if remoteAddress != "" { // remoteAddress=="" when we return initial tls.Config object when configuring server
logger.Debug("returning TLS config for connection", tag.Address(remoteAddress), tag.ServerName(serverName))
}
return auth.NewTLSConfigWithCertsAndCAs(
clientAuthType,
[]tls.Certificate{*serverCert},
clientCaPool,
logger), nil
}
func newClientTLSConfig(
clientProvider CertProvider,
serverName string,
isAuthRequired bool,View on GitHub (pinned to bde624efd1)
Solutions
- Check the wrapped error for the root cause (path, permissions, PEM decode) and fix the client CA source.
- Ensure clientCADataFile (or inline clientCAData) contains a valid PEM CA bundle.
- Confirm the CA bundle includes the CA that actually signed your client certificates.
- If mTLS is not needed, set requireClientAuth=false so the CA fetch is skipped.
Example fix
// before serverTLS: requireClientAuth: true # clientCADataFile missing // after serverTLS: requireClientAuth: true clientCADataFile: /etc/temporal/tls/client-ca.pem
Defensive patterns
Strategy: validation
Validate before calling
caPEM, err := os.ReadFile(cfg.ClientCADataFile)
if err != nil { return fmt.Errorf("client CA unreadable: %w", err) }
if !hasPEMCert(caPEM) { return errors.New("client CA bundle has no certificates") } Try / catch
cfg, err := getServerTLSConfigFromCertProvider(...)
if err != nil && strings.Contains(err.Error(), "failed to fetch client CAs") {
// disable mTLS only if policy allows; otherwise fail fast
logger.Fatal("client CA pool unavailable for mTLS", "cause", err)
} Prevention
- Ship the client CA bundle in the same secret/volume lifecycle as the server cert.
- Confirm the bundle signs all client certs you intend to accept.
- Run a pre-start config validation that decodes the CA pool.
When it happens
Trigger: Server TLS config built with requireClientAuth=true and the provider's client-CA file/data is missing, unreadable, or contains no parseable certificates (propagating errors like 390 from parseCert/buildCAPool).
Common situations: mTLS enabled but ClientCA (clientCADataFile / clientCAData) not configured or pointing to a wrong path; CA bundle file empty after secret rotation; clients authenticate with certs issued by a CA whose bundle failed to load.
Related errors
- unable to read client certificate file
- unable to decode client certificate
- failed to load tls x509 key pair: %v
- loading server tls certificate failed: %v
- failed to load client ca: %v
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/66d729f1717f7dcd.
Report an issue: GitHub.