hyperledger/fabric · error
chaincode tls key not provided
Error message
chaincode tls key not provided
What it means
When TLS is required and client authentication (mutual TLS) is also required, the peer needs the chaincode's client TLS private key to present in the handshake; connection.json without `client_key` cannot form a mutual-TLS dial.
Source
Thrown at core/container/externalbuilder/instance.go:95
func (c *ChaincodeServerUserData) ChaincodeServerInfo(cryptoDir string) (*ccintf.ChaincodeServerInfo, error) {
if c.Address == "" {
return nil, errors.New("chaincode address not provided")
}
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)}View on GitHub (pinned to 2736b63f8f)
Solutions
- Set `client_key` in connection.json to the PEM-encoded client TLS private key
- If mutual TLS is not needed, set client_auth_required to false
- Ensure the release script/template includes all four TLS fields (client_key, client_cert, root_cert, address)
Example fix
// before
{"tls_required":true,"client_auth_required":true,"client_cert":"cert.pem"}
// after
{"tls_required":true,"client_auth_required":true,"client_cert":"cert.pem","client_key":"key.pem","root_cert":"root.pem"} Defensive patterns
Strategy: validation
Validate before calling
var ud ChaincodeServerUserData
json.Unmarshal(connJSON, &ud)
if ud.TLSRequired && ud.ClientAuthRequired && ud.ClientKey == "" {
return errors.New("client_key PEM required for mutual TLS")
} Try / catch
info, err := ud.ChaincodeServerInfo(cryptoDir)
if err != nil && strings.Contains(err.Error(), "tls key not provided") {
return fmt.Errorf("provide client_key in connection.json or disable client_auth_required: %w", err)
} Prevention
- Emit client_key, client_cert, and root_cert together when client_auth_required is true
- Never enable client_auth_required without distributing the client key
- Validate connection.json TLS fields before launching the chaincode
When it happens
Trigger: connection.json has tls_required and client_auth_required true, but `client_key` is empty when ChaincodeServerInfo assembles the client SecOpts.
Common situations: Release step emitted certs but not the key; key mounted but path/env not passed into connection.json; user intentionally omitted private key for security but enabled client auth.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- chaincode tls cert 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/fa46fe65ceaf8e9f.
Report an issue: GitHub.