hyperledger/fabric · error
chaincode tls cert not provided
Error message
chaincode tls cert not provided
What it means
With clientAuthRequired enabled, the peer must present a client certificate during the mutual-TLS handshake with the chaincode server; connection.json lacking `client_cert` makes the required credential unavailable.
Source
Thrown at core/container/externalbuilder/instance.go:98
}
connInfo := &ccintf.ChaincodeServerInfo{Address: c.Address}
connInfo.ClientConfig.DialTimeout = time.Duration(c.DialTimeout)
if connInfo.ClientConfig.DialTimeout == 0 {
connInfo.ClientConfig.DialTimeout = DialTimeout
}
// we can expose this if necessary
connInfo.ClientConfig.KaOpts = comm.DefaultKeepaliveOptions
if !c.TLSRequired {
return connInfo, nil
}
if c.ClientAuthRequired && c.ClientKey == "" {
return nil, errors.New("chaincode tls key not provided")
}
if c.ClientAuthRequired && c.ClientCert == "" {
return nil, errors.New("chaincode tls cert not provided")
}
if c.RootCert == "" {
return nil, errors.New("chaincode tls root cert not provided")
}
connInfo.ClientConfig.SecOpts.UseTLS = true
if c.ClientAuthRequired {
connInfo.ClientConfig.SecOpts.RequireClientCert = true
connInfo.ClientConfig.SecOpts.Certificate = []byte(c.ClientCert)
connInfo.ClientConfig.SecOpts.Key = []byte(c.ClientKey)
connInfo.ClientConfig.SecOpts.ServerNameOverride = c.Domain
}
connInfo.ClientConfig.SecOpts.ServerRootCAs = [][]byte{[]byte(c.RootCert)}
return connInfo, nil
}View on GitHub (pinned to 2736b63f8f)
Solutions
- Set `client_cert` to the PEM-encoded client TLS certificate matching client_key
- If client auth is unnecessary, set client_auth_required to false
- Regenerate connection.json from the builder's release template including cert+key+root cert
Example fix
// before
{"client_auth_required":true,"client_key":"key.pem"}
// after
{"client_auth_required":true,"client_key":"key.pem","client_cert":"cert.pem"} Defensive patterns
Strategy: validation
Validate before calling
var ud ChaincodeServerUserData
json.Unmarshal(connJSON, &ud)
if ud.TLSRequired && ud.ClientAuthRequired && ud.ClientCert == "" {
return errors.New("client_cert PEM required for mutual TLS")
}
block, _ := pem.Decode([]byte(ud.ClientCert))
if block == nil || block.Type != "CERTIFICATE" { return errors.New("client_cert is not a PEM certificate") } Try / catch
info, err := ud.ChaincodeServerInfo(cryptoDir)
if err != nil && strings.Contains(err.Error(), "tls cert not provided") {
return fmt.Errorf("provide client_cert in connection.json or disable client_auth_required: %w", err)
} Prevention
- Generate cert+key as a pair and emit both fields together
- PEM-decode fields in CI to catch swapped/missing certs
- Keep a connection.json template listing every required TLS field
When it happens
Trigger: connection.json sets tls_required and client_auth_required true with a client_key present, but `client_cert` is empty in ChaincodeServerInfo.
Common situations: Partial TLS fields in connection.json; cert and key files swapped or only key copied; release script templating bug dropping the cert field.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- chaincode tls key not provided
- chaincode tls root cert not provided
- client didn't include its TLS cert hash
- client didn't send a TLS certificate
- claimed TLS cert hash is %v but actual TLS cert hash is %v
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/40b0d60b2fa8e8a7.
Report an issue: GitHub.