temporalio/temporal · error
client auth required, but no certificate provided
Error message
client auth required, but no certificate provided
What it means
In newClientTLSConfig, when client auth (mTLS) is required, the fetcher calls clientProvider.FetchClientCertificate(isWorker). If the provider returns success but a nil certificate — meaning it is configured with no client cert available — this explicit error is raised. It prevents silently starting mTLS handshakes with no client identity.
Source
Thrown at common/rpc/encryption/local_store_tls_provider.go:390
) (*tls.Config, error) {
// Optional ServerCA for client if not already trusted by host
serverCa, err := clientProvider.FetchServerRootCAsForClient(isWorker)
if err != nil {
return nil, fmt.Errorf("failed to load client ca: %v", err)
}
var getCert tlsCertFetcher
// mTLS enabled, present certificate
if isAuthRequired {
getCert = func() (*tls.Certificate, error) {
cert, err := clientProvider.FetchClientCertificate(isWorker)
if err != nil {
return nil, err
}
if cert == nil {
return nil, fmt.Errorf("client auth required, but no certificate provided")
}
return cert, nil
}
}
return auth.NewDynamicTLSClientConfig(
getCert,
serverCa,
serverName,
enableHostVerification,
), nil
}
func (s *localStoreTlsProvider) timerCallback() {
for {
select {
case <-s.stop:
returnView on GitHub (pinned to bde624efd1)
Solutions
- Configure client cert/key data (certDataFile/certData and keyDataFile/keyData) for the relevant client group (internode or frontend).
- Obtain a client certificate issued by the server's client CA and mount it for the process.
- If mTLS is not intended, disable requireClientAuth on the server so clients are not asked for certificates.
- Verify the cert file is populated (not an empty secret) and matches the key.
Example fix
// before
clientTLS:
internode:
serverName: tls-server # no client cert configured
// after
clientTLS:
internode:
serverName: tls-server
certDataFile: /etc/temporal/tls/client.pem
keyDataFile: /etc/temporal/tls/client-key.pem Defensive patterns
Strategy: validation
Validate before calling
if isAuthRequired {
certPEM, err := os.ReadFile(cfg.CertDataFile)
if err != nil { return fmt.Errorf("client cert unreadable: %w", err) }
keyPEM, err := os.ReadFile(cfg.KeyDataFile)
if err != nil { return fmt.Errorf("client key unreadable: %w", err) }
if _, err := tls.X509KeyPair(certPEM, keyPEM); err != nil { return fmt.Errorf("invalid client keypair: %w", err) }
} Try / catch
tlsCfg, err := newClientTLSConfig(...)
if err != nil && strings.Contains(err.Error(), "client auth required, but no certificate provided") {
return fmt.Errorf("mTLS requested but client identity not configured: %w", err)
} Prevention
- Always configure cert+key whenever the server has requireClientAuth enabled.
- Check client cert expiry and renew before rotation windows.
- Keep client and server mTLS settings in sync in config review.
When it happens
Trigger: isAuthRequired=true (mutual TLS) but the localStore provider has no client certificate path/data configured, or the configured cert is absent so the fetcher returns (nil, nil).
Common situations: Server demands client certs but the client config only sets serverCA and serverName, omitting the client cert/key pair; cert file removed by rotation without config update; worker enabled for mTLS on the server side but client-side cert block left empty.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- unable to read client certificate file
- unable to decode client certificate
- failed to load tls x509 key pair: %v
- failed to fetch client CAs: %v
- URI is invalid
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/a3f6ddf3c5c1e464.
Report an issue: GitHub.