{"record":{"id":"8c48b6ce3426080e","repo":"hyperledger/fabric","slug":"session-binding-read-failed","errorCode":null,"errorMessage":"session binding read failed","messagePattern":"session binding read failed","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/common/cluster/clusterservice.go","lineNumber":132,"sourceCode":"\t\t}\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\t// Else, no error occurred, so we continue to the next iteration\n\t}\n}\n\nfunc (s *ClusterService) VerifyAuthRequest(stream orderer.ClusterNodeService_StepServer, request *orderer.ClusterNodeServiceStepRequest) (*orderer.NodeAuthRequest, error) {\n\tauthReq := request.GetNodeAuthrequest()\n\tif authReq == nil {\n\t\treturn nil, errors.New(\"invalid request object\")\n\t}\n\n\tbindingFieldsHash := GetSessionBindingHash(authReq)\n\n\ttlsBinding, err := GetTLSSessionBinding(stream.Context(), bindingFieldsHash)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"session binding read failed\")\n\t}\n\n\tif !bytes.Equal(tlsBinding, authReq.SessionBinding) {\n\t\treturn nil, errors.New(\"session binding mismatch\")\n\t}\n\n\tmsg, err := asn1.Marshal(AuthRequestSignature{\n\t\tVersion:        int64(authReq.Version),\n\t\tTimestamp:      EncodeTimestamp(authReq.Timestamp),\n\t\tFromId:         strconv.FormatUint(authReq.FromId, 10),\n\t\tToId:           strconv.FormatUint(authReq.ToId, 10),\n\t\tSessionBinding: tlsBinding,\n\t\tChannel:        authReq.Channel,\n\t})\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"ASN encoding failed\")\n\t}\n","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/common/cluster/clusterservice.go#L114-L150","documentation":"VerifyAuthRequest derives the expected TLS session binding (a hash over binding fields computed from the gRPC stream context) via GetTLSSessionBinding and wraps any failure with 'session binding read failed'. It means the server could not compute or read the binding from the connection itself — typically because TLS handshake data is missing from the context.","triggerScenarios":"The Step stream arrives without mutual TLS (TLS disabled on the listener or the client not presenting a certificate), so GetTLSSessionBinding cannot extract the required handshake material.","commonSituations":"Orderer or cluster communication deployed without TLS while node authentication requires it; test environments disabling TLS; misconfigured General.TLS settings; a terminating proxy that ends TLS before the orderer, removing the session binding data.","solutions":["Enable mutual TLS on the orderer (General.TLS.Enabled: true) and require client certs, so the binding can be computed from the session.","Remove any TLS-terminating proxy in front of ordering nodes, or switch to TLS passthrough.","Verify the client presents a valid TLS certificate and that CA trust is configured on both sides.","Inspect GetTLSSessionBinding / the wrapped underlying error in the orderer logs to identify exactly which binding field is missing."],"exampleFix":"# before\nGeneral:\n  TLS:\n    Enabled: false\n# after\nGeneral:\n  TLS:\n    Enabled: true\n    PrivateKey: /path/tls/server.key\n    Certificate: /path/tls/server.crt\n    RootCAs: [/path/tls/ca.crt]\n    ClientRootCAs: [/path/tls/ca.crt]","handlingStrategy":"try-catch","validationCode":"// client side: confirm mTLS is configured before connecting\nif tlsConfig == nil || len(tlsConfig.Certificates) == 0 {\n    return errors.New(\"cluster connections require mutual TLS with a client certificate\")\n}","typeGuard":null,"tryCatchPattern":"authReq, err := svc.VerifyAuthRequest(stream, request)\nif err != nil {\n    var wrapped interface{ Unwrap() error }\n    if errors.As(err, &wrapped) && strings.Contains(err.Error(), \"session binding read failed\") {\n        // underlying GetTLSSessionBinding error is wrapped — log it and check TLS setup\n    }\n    return err\n}","preventionTips":["Enable mTLS on ordering nodes and require client certificates","Use TLS passthrough, not termination, on any proxy in front of orderers","Keep General.TLS settings consistent across the cluster","Log the wrapped underlying error to identify the missing binding field"],"tags":["fabric","orderer","tls","authentication","cluster"],"backgroundTag":"tls-session-binding-failed","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"}