{"record":{"id":"f48d186522fd3bff","repo":"grpc/grpc-go","slug":"lrs-unexpected-message-type-t","errorCode":null,"errorMessage":"lrs: unexpected message type %T","messagePattern":"lrs: unexpected message type %T","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/clients/lrsclient/lrs_stream.go","lineNumber":214,"sourceCode":"}\n\n// recvFirstLoadStatsResponse receives the first LoadStatsResponse from the LRS\n// server.  Returns the following:\n//   - a list of cluster names requested by the server or an empty slice if the\n//     server requested for load from all clusters\n//   - the load reporting interval, and\n//   - any error encountered\nfunc (lrs *streamImpl) recvFirstLoadStatsResponse(stream clients.Stream) ([]string, time.Duration, error) {\n\tr, err := stream.Recv()\n\tif err != nil {\n\t\treturn nil, 0, fmt.Errorf(\"lrs: failed to receive first LoadStatsResponse: %v\", err)\n\t}\n\tvar resp v3lrspb.LoadStatsResponse\n\tif err := proto.Unmarshal(r, &resp); err != nil {\n\t\tif lrs.logger.V(2) {\n\t\t\tlrs.logger.Infof(\"Failed to unmarshal response to LoadStatsResponse: %v\", err)\n\t\t}\n\t\treturn nil, time.Duration(0), fmt.Errorf(\"lrs: unexpected message type %T\", r)\n\t}\n\tif lrs.logger.V(perRPCVerbosityLevel) {\n\t\tlrs.logger.Infof(\"Received first LoadStatsResponse: %s\", pretty.ToJSON(&resp))\n\t}\n\n\tinternal := resp.GetLoadReportingInterval()\n\tif internal.CheckValid() != nil {\n\t\treturn nil, 0, fmt.Errorf(\"lrs: invalid load_reporting_interval: %v\", err)\n\t}\n\tloadReportingInterval := internal.AsDuration()\n\n\tclusters := resp.Clusters\n\tif resp.SendAllClusters {\n\t\t// Return an empty slice to send stats for all clusters.\n\t\tclusters = []string{}\n\t}\n\n\treturn clusters, loadReportingInterval, nil","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/xds/clients/lrsclient/lrs_stream.go#L196-L232","documentation":"Returned by recvFirstLoadStatsResponse when stream.Recv() succeeds but proto.Unmarshal of the bytes into envoy.service.load_stats.v3.LoadStatsResponse fails. This means the server sent bytes on the LRS stream that are not a valid LoadStatsResponse protobuf. The runner treats it as a stream failure and retries with backoff.","triggerScenarios":"Connecting to an endpoint that speaks a different protocol on the StreamLoadStats path (e.g. an HTTP/1 error page, an ADS/LRS version mismatch, or a proxy injecting HTML), or a buggy/non-conformant LRS server that emits an unrelated protobuf on the stream.","commonSituations":"Pointing the LRS client at a v2 LRS server while using v3 protos, a load balancer/proxy returning a plaintext error body over the otherwise-HTTP/2 stream, or an Envoy/control-plane build that serializes a different message type for StreamLoadStats.","solutions":["Confirm the remote is an xDS v3 management server that implements envoy.service.load_stats.v3.LoadReportingService.","Capture the stream with grpcurl --protocol h2 against the LRS service path to see what the server actually returns.","Check for an intermediating proxy/LB that may rewrite the body, and bypass it to test.","Ensure client and server use the same go-control-plane / grpc-go proto versions for load_stats/v3."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Point the LRS client only at servers implementing envoy.service.load_stats.v3.LoadReportingService.","Keep client and server on the same xDS major version (v3).","Avoid routing the LRS stream through proxies that rewrite bodies."],"tags":["grpc","xds","lrs","protobuf","protocol-mismatch"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}