temporalio/temporal · critical

loading server tls certificate failed: %v

Error message

loading server tls certificate failed: %v

What it means

getServerTLSConfigFromCertProvider fetches the server certificate from the configured cert provider and wraps any FetchServerCertificate failure as "loading server tls certificate failed: %v". It is raised during TLS config construction for the server (newServerTLSConfig or a callback) when the local-store cert provider cannot supply a server cert. The underlying provider error is formatted with %v, so the chain is not preserved.

Source

Thrown at common/rpc/encryption/local_store_tls_provider.go:333

			return getServerTLSConfigFromCertProvider(certProvider, clientAuthRequired, remoteAddress, c.ServerName, logger)
		}
		return getServerTLSConfigFromCertProvider(certProvider, clientAuthRequired, remoteAddress, c.ServerName, logger)
	}

	return tlsConfig, nil
}

func getServerTLSConfigFromCertProvider(
	certProvider CertProvider,
	requireClientAuth bool,
	remoteAddress string,
	serverName string,
	logger log.Logger) (*tls.Config, error) {

	// Get serverCert from disk
	serverCert, err := certProvider.FetchServerCertificate()
	if err != nil {
		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)

View on GitHub (pinned to bde624efd1)

Solutions

  1. Inspect the wrapped %v text for the root cause (file not found, PEM decode, x509 parse) and fix the underlying provider input.
  2. Verify serverTLS.certFilePath and keyFilePath point to existing, readable PEM files.
  3. Check file permissions and that the secret/volume mount is present before service start.
  4. Validate the cert/key pair matches (openssl x509 -noout -modulus vs openssl rsa -noout -modulus).

Example fix

// before
serverTLS:
  certFilePath: /etc/certs/server.crt   # file does not exist
// after
serverTLS:
  certFilePath: /etc/temporal/tls/server.pem
  keyFilePath: /etc/temporal/tls/server-key.pem
Defensive patterns

Strategy: validation

Validate before calling

cert, err := os.ReadFile(cfg.CertFilePath)
if err != nil { return fmt.Errorf("server cert unreadable: %w", err) }
key, err := os.ReadFile(cfg.KeyFilePath)
if err != nil { return fmt.Errorf("server key unreadable: %w", err) }
if _, err := tls.X509KeyPair(cert, key); err != nil { return fmt.Errorf("bad server cert/key pair: %w", err) }

Try / catch

cfg, err := getServerTLSConfigFromCertProvider(...)
if err != nil && strings.Contains(err.Error(), "loading server tls certificate failed") {
    logger.Fatal("cannot start: server TLS cert invalid", "cause", err)
}

Prevention

When it happens

Trigger: Server startup (newServerTLSConfig) or a refresh callback where certProvider.FetchServerCertificate() returns an error — e.g. cert file missing/unreadable, PEM decode failure (error 390), or x509 parse failure.

Common situations: Temporal server starting with a bad localStore TLS config: wrong CertFilePath/KeyFilePath, secrets not mounted, file permission denied, malformed certificate, or the cert provider's watch path pointing to a nonexistent directory.

Understand the failure class

Related errors


AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01). Data as JSON: /api/errors/0f4786199209cb21. Report an issue: GitHub.