hyperledger/fabric · error
client didn't include its TLS cert hash
Error message
client didn't include its TLS cert hash
What it means
mutualTLSBinding checks that the client message carries a TLS cert hash field. An empty claimedTLScertHash means the client did not populate the cert_hash in its request, which is required to bind the message to its TLS channel.
Source
Thrown at common/deliver/binding.go:52
inspectMessage = noopBinding
}
return func(ctx context.Context, msg proto.Message) error {
if msg == nil {
return errors.New("message is nil")
}
return inspectMessage(ctx, extractTLSCertHash(msg))
}
}
// mutualTLSBinding enforces the client to send its TLS cert hash in the message,
// and then compares it to the computed hash that is derived
// from the gRPC context.
// In case they don't match, or the cert hash is missing from the request or
// there is no TLS certificate to be excavated from the gRPC context,
// an error is returned.
func mutualTLSBinding(ctx context.Context, claimedTLScertHash []byte) error {
if len(claimedTLScertHash) == 0 {
return errors.Errorf("client didn't include its TLS cert hash")
}
actualTLScertHash := util.ExtractCertificateHashFromContext(ctx)
if len(actualTLScertHash) == 0 {
return errors.Errorf("client didn't send a TLS certificate")
}
if !bytes.Equal(actualTLScertHash, claimedTLScertHash) {
return errors.Errorf("claimed TLS cert hash is %v but actual TLS cert hash is %v", claimedTLScertHash, actualTLScertHash)
}
return nil
}
// noopBinding is a BindingInspector that always returns nil
func noopBinding(_ context.Context, _ []byte) error {
return nil
}
View on GitHub (pinned to 2736b63f8f)
Solutions
- Update the client SDK/CLI to a version that sets the TLS cert hash in requests
- Ensure the client connects over TLS with a client certificate so a hash can be computed
- If binding is not needed, configure the server to disable mutual TLS binding (mutualTLS=false)
Defensive patterns
Strategy: validation
Validate before calling
if len(msg.TLSCertHash) == 0 {
return errors.New("client must set TLSCertHash when mutual TLS binding is enabled")
} Try / catch
if err := inspector(ctx, msg); err != nil {
if strings.Contains(err.Error(), "didn't include its TLS cert hash") {
return status.Error(codes.Unauthenticated, "update client SDK to set TLS cert hash")
}
return err
} Prevention
- Use an SDK version that populates the TLS cert hash
- Enable mutual TLS on the client so a hash can always be computed
- Only disable mutualTLS binding when the deployment explicitly doesn't need replay protection
When it happens
Trigger: Deliver or broadcast requests sent with mutual TLS enabled but without the TLS cert hash set in the message (e.g., Envelope with missing cert_hash in ChannelHeader-related binding).
Common situations: Older SDKs or CLI tools that don't compute/populate the TLS cert hash; clients built without TLS binding support connecting to an orderer with mutualTLS binding enforced.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- client didn't send a TLS certificate
- claimed TLS cert hash is %v but actual TLS cert hash is %v
- no TLS certificate sent
- message is nil
- chaincode tls key not provided
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/48b1f8274e6c294a.
Report an issue: GitHub.