temporalio/temporal · error
failed to load CA files: %v
Error message
failed to load CA files: %v
What it means
registerTLSConfig in the MySQL session package reads the configured CA PEM file (cfg.TLS.CaFile) to build the root certificate pool for the connection; if os.ReadFile fails, the error is wrapped as "failed to load CA files". The MySQL client cannot establish verified TLS without this file.
Source
Thrown at common/persistence/sql/sqlplugin/mysql/session/session.go:216
return key, value
default:
return inkey, invalue
}
}
func registerTLSConfig(cfg *config.SQL) error {
if cfg.TLS == nil || !cfg.TLS.Enabled {
return nil
}
// TODO: create a way to set MinVersion and CipherSuites via cfg.
tlsConfig := auth.NewTLSConfigForServer(cfg.TLS.ServerName, cfg.TLS.EnableHostVerification)
if cfg.TLS.CaFile != "" {
rootCertPool := x509.NewCertPool()
pem, err := os.ReadFile(cfg.TLS.CaFile)
if err != nil {
return fmt.Errorf("failed to load CA files: %v", err)
}
if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
return fmt.Errorf("failed to append CA file")
}
tlsConfig.RootCAs = rootCertPool
}
if cfg.TLS.CertFile != "" && cfg.TLS.KeyFile != "" {
clientCert := make([]tls.Certificate, 0, 1)
certs, err := tls.LoadX509KeyPair(
cfg.TLS.CertFile,
cfg.TLS.KeyFile,
)
if err != nil {
return fmt.Errorf("failed to load tls x509 key pair: %v", err)
}
clientCert = append(clientCert, certs)
tlsConfig.Certificates = clientCertView on GitHub (pinned to bde624efd1)
Solutions
- Verify the path in TLS.CaFile exists and is readable by the Temporal process user (ls -l / check permissions).
- Use an absolute path in containerized deployments and ensure the file is mounted (e.g., via a Kubernetes secret volume).
- Fix ownership/permissions (chmod/chown) so the service account can read the PEM file.
- If TLS verification is not required for the environment, remove the CaFile setting — but prefer fixing the mount for security.
Example fix
// before (config) tls: caFile: certs/ca.pem // after tls: caFile: /etc/temporal/certs/ca.pem # absolute path, verified mounted & readable
Defensive patterns
Strategy: validation
Validate before calling
caPath := cfg.TLS.CaFile
if fi, err := os.Stat(caPath); err != nil || fi.Size() == 0 {
return fmt.Errorf("CA file %q missing or empty", caPath)
}
if f, err := os.Open(caPath); err != nil {
return fmt.Errorf("CA file %q not readable: %v", caPath, err)
} else { f.Close() } Try / catch
if err := connectDB(cfg); err != nil {
if strings.Contains(err.Error(), "failed to load CA files") {
// fix caFile path/mount/permissions before reconnect
}
return err
} Prevention
- Use absolute paths for TLS files in containers.
- Mount CA files as read-only volumes (K8s secrets) and verify at pod startup.
- Add a startup check that stats and reads every configured TLS file.
When it happens
Trigger: createConnection -> registerTLSConfig with a non-empty TLS.CaFile that points to a nonexistent, unreadable, or otherwise un-openable file path.
Common situations: Typo in the CA file path in config; file not mounted into a container (missing volume mount); permission denied for the service user; relative path used with a different working directory in a container.
Related errors
- failed to append CA file
- failed to load tls x509 key pair: %v
- failed to register tls config: %v
- only one of keyData or keyFile properties should be specifie
- only one of caData or caFile properties should be specified
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/edbc018c97d2d444.
Report an issue: GitHub.