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

  1. Set `client_cert` to the PEM-encoded client TLS certificate matching client_key
  2. If client auth is unnecessary, set client_auth_required to false
  3. 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

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

Related errors


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