hyperledger/fabric · error
TLS is active but chaincode %s didn't send certificate
Error message
TLS is active but chaincode %s didn't send certificate
What it means
When mutual TLS is enabled between peer and chaincode, the Authenticator requires the chaincode's TLS client certificate during registration. If the stream's gRPC context carries no certificate hash (the client presented no certificate, or TLS metadata is absent), registration is rejected with 'TLS is active but chaincode %s didn't send certificate'.
Source
Thrown at core/chaincode/accesscontrol/access.go:78
func (ac *Authenticator) authenticate(msg *pb.ChaincodeMessage, stream grpc.ServerStream) error {
if msg.Type != pb.ChaincodeMessage_REGISTER {
logger.Warning("Got message", msg, "but expected a ChaincodeMessage_REGISTER message")
return errors.New("First message needs to be a register")
}
chaincodeID := &pb.ChaincodeID{}
err := proto.Unmarshal(msg.Payload, chaincodeID)
if err != nil {
logger.Warning("Failed unmarshalling message:", err)
return err
}
ccName := chaincodeID.Name
// Obtain certificate from stream
hash := extractCertificateHashFromContext(stream.Context())
if len(hash) == 0 {
errMsg := fmt.Sprintf("TLS is active but chaincode %s didn't send certificate", ccName)
logger.Warning(errMsg)
return errors.New(errMsg)
}
// Look it up in the mapper
registeredName := ac.mapper.lookup(certHash(hash))
if registeredName == "" {
errMsg := fmt.Sprintf("Chaincode %s with given certificate hash %v not found in registry", ccName, hash)
logger.Warning(errMsg)
return errors.New(errMsg)
}
if registeredName != ccName {
errMsg := fmt.Sprintf("Chaincode %s with given certificate hash %v belongs to a different chaincode", ccName, hash)
logger.Warning(errMsg)
return errors.New(errMsg)
}
logger.Debug("Chaincode", ccName, "'s authentication is authorized")
return nil
}
View on GitHub (pinned to 2736b63f8f)
Solutions
- Configure the chaincode to use TLS with its client certificate (set CORE_CHAINCODE_TLS_CERT / CORE_CHAINCODE_TLS_KEY to the cert/key files).
- Ensure the chaincode's connection address uses the TLS port and the peer's chaincode TLS settings match (peer.chaincode.cert.enabled).
- If running in a container, verify the TLS files are mounted and readable, and the chaincode connects over TLS not plaintext.
- Remove any TLS-terminating proxy between chaincode and peer, or re-sign at the peer side so client certs reach the peer.
Example fix
// before: chaincode started without TLS CORE_CHAINCODE_ID_NAME=mycc:1.0 /bin/chaincode -peer.address peer:7052 // after: chaincode started with TLS certs CORE_CHAINCODE_ID_NAME=mycc:1.0 CORE_CHAINCODE_TLS_CERT=/certs/tls.crt CORE_CHAINCODE_TLS_KEY=/certs/tls.key /bin/chaincode -peer.address peer:7052
Defensive patterns
Strategy: validation
Validate before calling
// before connecting, confirm TLS material is present
if _, err := tls.LoadX509KeyPair(tlsCertPath, tlsKeyPath); err != nil {
return fmt.Errorf("chaincode TLS cert/key missing: %w", err)
} Type guard
func tlsCredentialsPresent(certPath, keyPath string) bool {
_, err := tls.LoadX509KeyPair(certPath, keyPath)
return err == nil
} Try / catch
if err := authenticate(msg, stream); err != nil {
if strings.Contains(err.Error(), "didn't send certificate") {
// re-dial the peer with tls.Credentials{Certificates: clientCerts}
}
} Prevention
- Match chaincode TLS settings to the peer's chaincode.cert.enabled configuration
- Mount TLS cert/key files into the chaincode container and point CORE_CHAINCODE_TLS_CERT/KEY at them
- Avoid TLS-terminating proxies between chaincode and peer
- Use the TLS-enabled peer address when mtls is on
When it happens
Trigger: A chaincode registers over a connection where extractCertificateHashFromContext finds no client certificate: TLS client auth not configured on the chaincode's connection, or the chaincode's side of the gRPC connection was established without TLS.
Common situations: Chaincode configured with TLS disabled while the peer runs with peer.chaincode.cert.enabled=true (mtls); a dev-mode chaincode or local runner not presenting its TLS keypair; a proxy/load balancer terminating TLS so the peer never sees the client cert.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Chaincode %s with given certificate hash %v not found in reg
- Chaincode %s with given certificate hash %v belongs to a dif
- First message needs to be a register
- loading client cert/key pair: %s
- cannot load client cert for consenter %s:%d: %s
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/947c5dda7e4a2a18.
Report an issue: GitHub.