{"record":{"id":"9374600222ef6f34","repo":"hyperledger/fabric","slug":"no-tls-certificate-sent","errorCode":null,"errorMessage":"no TLS certificate sent","messagePattern":"no TLS certificate sent","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/common/cluster/comm.go","lineNumber":103,"sourceCode":"// requestContext identifies the sender and channel of the request and returns\n// it wrapped in a requestContext\nfunc (c *Comm) requestContext(ctx context.Context, msg proto.Message) (*requestContext, error) {\n\tchannel := c.ChanExt.TargetChannel(msg)\n\tif channel == \"\" {\n\t\treturn nil, errors.Errorf(\"badly formatted message, cannot extract channel\")\n\t}\n\n\tc.Lock.RLock()\n\tmapping, exists := c.Chan2Members[channel]\n\tc.Lock.RUnlock()\n\n\tif !exists {\n\t\treturn nil, errors.Errorf(\"channel %s doesn't exist\", channel)\n\t}\n\n\tcert := util.ExtractRawCertificateFromContext(ctx)\n\tif len(cert) == 0 {\n\t\treturn nil, errors.Errorf(\"no TLS certificate sent\")\n\t}\n\n\tstub := mapping.LookupByClientCert(cert)\n\tif stub == nil {\n\t\treturn nil, errors.Errorf(\"certificate extracted from TLS connection isn't authorized\")\n\t}\n\treturn &requestContext{\n\t\tchannel: channel,\n\t\tsender:  stub.ID,\n\t}, nil\n}\n\n// Remote obtains a RemoteContext linked to the destination node on the context\n// of a given channel\nfunc (c *Comm) Remote(channel string, id uint64) (*RemoteContext, error) {\n\tc.Lock.RLock()\n\tdefer c.Lock.RUnlock()\n","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/common/cluster/comm.go#L85-L121","documentation":"The orderer requires mutual TLS on cluster communication: the sender's TLS client certificate proves the sender's identity. util.ExtractRawCertificateFromContext(ctx) returned empty because the incoming gRPC request's context carried no client certificate, so the sender cannot be authenticated and the request is rejected.","triggerScenarios":"A cluster Step/Submit request arrives over a connection that did not present a TLS client certificate — TLS client auth disabled or misconfigured, or the request was not routed through the mutual-TLS gRPC server.","commonSituations":"Orderer TLS enabled but clientAuthRequired not set (or vice versa) in orderer.yaml; a test/tool connecting with one-way TLS; a proxy/LB terminating TLS and stripping client certs; sender built without TLS credentials.","solutions":["Enable mutual TLS: set General.TLS.ClientAuthRequired: true in orderer.yaml and configure the client cert on the sender side","Ensure the sender's gRPC dial includes its TLS client keypair (tls.Config{Certificates: ...})","Check no proxy/load balancer terminates TLS between sender and orderer, dropping client certs","Confirm General.TLS.Enabled is true on both ends and certs are signed by the same CA"],"exampleFix":"// before (sender dials without client cert)\nconn, _ := grpc.Dial(addr, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})))\n// after\ncert, _ := tls.LoadX509KeyPair(\"client.crt\", \"client.key\")\ntlsCfg := &tls.Config{Certificates: []tls.Certificate{cert}, RootCAs: caPool}\nconn, _ := grpc.Dial(addr, grpc.WithTransportCredentials(credentials.NewTLS(tlsCfg)))","handlingStrategy":"validation","validationCode":"// Sender-side: fail fast if mutual TLS is not fully configured\nfunc requireMutualTLS(cfg *tls.Config) error {\n    if cfg == nil || len(cfg.Certificates) == 0 {\n        return errors.New(\"client certificate required for cluster communication\")\n    }\n    if cfg.RootCAs == nil { return errors.New(\"server CA pool required\") }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if _, err := comm.Remote(channel, id); err != nil {\n    if strings.Contains(err.Error(), \"no TLS certificate sent\") {\n        // reconfigure TLS creds and redial\n        creds := credentials.NewTLS(loadMutualTLSConfig())\n        conn, err = grpc.Dial(addr, grpc.WithTransportCredentials(creds))\n    }\n}","preventionTips":["Set General.TLS.ClientAuthRequired: true and provision client certs on every orderer","Always pass the client keypair in the gRPC dial's tls.Config","Avoid TLS-terminating proxies in front of cluster ports","Rotate certs on both ends in lockstep with channel config updates"],"tags":["tls","mutual-tls","grpc","hyperledger-fabric"],"backgroundTag":"missing-tls-client-cert","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"}