{"record":{"id":"238fee49677af07d","repo":"hyperledger/fabric","slug":"failed-extracting-stream-context","errorCode":null,"errorMessage":"failed extracting stream context","messagePattern":"failed extracting stream context","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/common/cluster/util.go","lineNumber":701,"sourceCode":"\t\treturn nil, errors.Wrap(err, \"failed generating TLS Binding material\")\n\t}\n\treturn tlsBinding, nil\n}\n\nfunc GetSessionBindingHash(authReq *orderer.NodeAuthRequest) []byte {\n\treturn util.ComputeSHA256(util.ConcatenateBytes(\n\t\t[]byte(strconv.FormatUint(uint64(authReq.Version), 10)),\n\t\tEncodeTimestamp(authReq.Timestamp),\n\t\t[]byte(strconv.FormatUint(authReq.FromId, 10)),\n\t\t[]byte(strconv.FormatUint(authReq.ToId, 10)),\n\t\t[]byte(authReq.Channel),\n\t))\n}\n\nfunc GetTLSSessionBinding(ctx context.Context, bindingPayload []byte) ([]byte, error) {\n\tpeerInfo, ok := peer.FromContext(ctx)\n\tif !ok {\n\t\treturn nil, errors.New(\"failed extracting stream context\")\n\t}\n\tconnState := peerInfo.AuthInfo.(credentials.TLSInfo).State\n\n\ttlsBinding, err := exportKM(connState, KeyingMaterialLabel, bindingPayload)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"failed exporting keying material\")\n\t}\n\n\treturn tlsBinding, nil\n}\n\nfunc VerifySignature(identity, msgHash, signature []byte) error {\n\tblock, _ := pem.Decode(identity)\n\tif block == nil {\n\t\treturn errors.New(\"pem decoding failed\")\n\t}\n\n\tcert, err := x509.ParseCertificate(block.Bytes)","sourceCodeStart":683,"sourceCodeEnd":719,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/common/cluster/util.go#L683-L719","documentation":"GetTLSSessionBinding uses the gRPC peer package to pull authentication info from the incoming stream context. If the context carries no peer (peer.FromContext fails), there is no TLS session to derive keying material from, so the function aborts with this error. It guards the contract that a bound request must arrive over an authenticated gRPC stream.","triggerScenarios":"Calling GetTLSSessionBinding with a ctx that was not obtained from a real gRPC stream handler: a manually constructed context.Context, a context from a non-TLS/insecure gRPC connection, or a test harness that passes context.Background().","commonSituations":"Unit tests invoking the binding logic without a gRPC server; clients connecting over plaintext (no TLS credentials configured so peer.AuthInfo is absent); middleware that forwards a stripped context instead of the stream's context.","solutions":["Ensure the caller passes the ctx received from the gRPC stream handler (grpc.StreamServerInfo / ServerStream.Context()) rather than a synthesized context","Configure TLS on both sides of the gRPC channel so the server populates peer.AuthInfo (credentials.TLSInfo)","Verify the call path actually goes through the gRPC transport; a locally invoked function will have no peer","In tests, use credentials of a real in-process gRPC server (bufconn with TLS) or inject a peer.NewContext-wrapped context"],"exampleFix":"// before\ntlsBinding, err := cluster.GetTLSSessionBinding(context.Background(), payload)\n// after\nfunc (s *srv) Req(stream cluster.Stream) error {\n    ctx := stream.Context() // context from the authenticated gRPC stream\n    tlsBinding, err := cluster.GetTLSSessionBinding(ctx, payload)\n    ...\n}","handlingStrategy":"type-guard","validationCode":"_, ok := peer.FromContext(ctx)\nif !ok { return errors.New(\"no gRPC peer in context; cannot export TLS binding\") }","typeGuard":"func hasPeerContext(ctx context.Context) bool {\n    pi, ok := peer.FromContext(ctx)\n    return ok && pi != nil && pi.AuthInfo != nil\n}","tryCatchPattern":"binding, err := cluster.GetTLSSessionBinding(ctx, payload)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed extracting stream context\") {\n        // fall back or reject the request: context has no authenticated peer\n    }\n    return err\n}","preventionTips":["Always take ctx from the gRPC stream handler, never context.Background()","Require TLS on the gRPC server (grpc.Creds) so AuthInfo is populated","Add a startup check that the server transport security is enabled","In tests, build the context with peer.NewContext(ctx, &peer.Peer{AuthInfo: credentials.TLSInfo{}})"],"tags":["grpc","tls","context"],"backgroundTag":"grpc-peer-context-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"}