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

  1. Update the client SDK/CLI to a version that sets the TLS cert hash in requests
  2. Ensure the client connects over TLS with a client certificate so a hash can be computed
  3. 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

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

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/48b1f8274e6c294a. Report an issue: GitHub.