{"record":{"id":"947c5dda7e4a2a18","repo":"hyperledger/fabric","slug":"tls-is-active-but-chaincode-s-didn-t-send-certifi","errorCode":null,"errorMessage":"TLS is active but chaincode %s didn't send certificate","messagePattern":"TLS is active but chaincode (.+?) didn't send certificate","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/chaincode/accesscontrol/access.go","lineNumber":78,"sourceCode":"func (ac *Authenticator) authenticate(msg *pb.ChaincodeMessage, stream grpc.ServerStream) error {\n\tif msg.Type != pb.ChaincodeMessage_REGISTER {\n\t\tlogger.Warning(\"Got message\", msg, \"but expected a ChaincodeMessage_REGISTER message\")\n\t\treturn errors.New(\"First message needs to be a register\")\n\t}\n\n\tchaincodeID := &pb.ChaincodeID{}\n\terr := proto.Unmarshal(msg.Payload, chaincodeID)\n\tif err != nil {\n\t\tlogger.Warning(\"Failed unmarshalling message:\", err)\n\t\treturn err\n\t}\n\tccName := chaincodeID.Name\n\t// Obtain certificate from stream\n\thash := extractCertificateHashFromContext(stream.Context())\n\tif len(hash) == 0 {\n\t\terrMsg := fmt.Sprintf(\"TLS is active but chaincode %s didn't send certificate\", ccName)\n\t\tlogger.Warning(errMsg)\n\t\treturn errors.New(errMsg)\n\t}\n\t// Look it up in the mapper\n\tregisteredName := ac.mapper.lookup(certHash(hash))\n\tif registeredName == \"\" {\n\t\terrMsg := fmt.Sprintf(\"Chaincode %s with given certificate hash %v not found in registry\", ccName, hash)\n\t\tlogger.Warning(errMsg)\n\t\treturn errors.New(errMsg)\n\t}\n\tif registeredName != ccName {\n\t\terrMsg := fmt.Sprintf(\"Chaincode %s with given certificate hash %v belongs to a different chaincode\", ccName, hash)\n\t\tlogger.Warning(errMsg)\n\t\treturn errors.New(errMsg)\n\t}\n\n\tlogger.Debug(\"Chaincode\", ccName, \"'s authentication is authorized\")\n\treturn nil\n}\n","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/chaincode/accesscontrol/access.go#L60-L96","documentation":"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'.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: chaincode started without TLS\nCORE_CHAINCODE_ID_NAME=mycc:1.0 /bin/chaincode -peer.address peer:7052\n// after: chaincode started with TLS certs\nCORE_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","handlingStrategy":"validation","validationCode":"// before connecting, confirm TLS material is present\nif _, err := tls.LoadX509KeyPair(tlsCertPath, tlsKeyPath); err != nil {\n    return fmt.Errorf(\"chaincode TLS cert/key missing: %w\", err)\n}","typeGuard":"func tlsCredentialsPresent(certPath, keyPath string) bool {\n    _, err := tls.LoadX509KeyPair(certPath, keyPath)\n    return err == nil\n}","tryCatchPattern":"if err := authenticate(msg, stream); err != nil {\n    if strings.Contains(err.Error(), \"didn't send certificate\") {\n        // re-dial the peer with tls.Credentials{Certificates: clientCerts}\n    }\n}","preventionTips":["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"],"tags":["hyperledger-fabric","tls","mtls","chaincode","access-control"],"backgroundTag":"mtls-client-certificate-missing","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}