{"record":{"id":"036e7efe17671af4","repo":"grpc/grpc-go","slug":"lrs-failed-to-receive-first-loadstatsresponse-v","errorCode":null,"errorMessage":"lrs: failed to receive first LoadStatsResponse: %v","messagePattern":"lrs: failed to receive first LoadStatsResponse: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/xds/clients/lrsclient/lrs_stream.go","lineNumber":207,"sourceCode":"\t\treturn err\n\t}\n\terr = stream.Send(msg)\n\tif err == io.EOF {\n\t\treturn getStreamError(stream)\n\t}\n\treturn err\n}\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","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/xds/clients/lrsclient/lrs_stream.go#L189-L225","documentation":"Thrown by recvFirstLoadStatsResponse in the LRS client when stream.Recv() returns a non-nil error before the first LoadStatsResponse arrives. The gRPC LRS runner catches it (logs 'Reading from LRS streaming RPC failed'), returns nil, and backoff.RunF retries the whole stream with exponential backoff, so it is transient by design. It surfaces to a developer only if they instrument the stream directly or if retries keep failing.","triggerScenarios":"Calling lrsclient.ReportLoad against an LRS server that is unreachable, refuses the StreamLoadStats RPC, drops the connection, fails a TLS handshake, or never sends a first response (idle server). The error is the raw gRPC stream error from Recv on '/envoy.service.load_stats.v3.LoadReportingService/StreamLoadStats'.","commonSituations":"Wrong ServerURI or port in the LRS server identifier, missing/mismatched TLS credentials in the transport builder, LRS management server not actually implementing the LRS service, network partition or firewall between client and server, or the server closing the stream immediately (e.g. node rejected).","solutions":["Verify the ServerURI and port in the clients.ServerIdentifier passed to ReportLoad resolve and are reachable (e.g. grpcurl to the LRS service path).","Check that the TransportBuilder supplies credentials the LRS server accepts (mTLS/insecure as appropriate) and that the server speaks the v3 LRS service.","Inspect the wrapped %v cause: io.EOF/Unavailable points to connection/TLS, PermissionDenied/Unauthenticated to credentials, Unimplemented to a non-LRS server.","Confirm the management server is actually configured to serve load reports for the requested clusters; a server that never responds keeps the stream open without error, so a Recv error usually means the connection itself broke."],"exampleFix":"// before: server URI typo / wrong port\nsi := clients.ServerIdentifier{ServerURI: \"trafficdirector.googleapis.com:443\"}\nls, err := lrsClient.ReportLoad(si)\n\n// after: correct LRS endpoint + valid authority\nsi := clients.ServerIdentifier{\n  ServerURI: \"trafficdirector.googleapis.com:443\",\n  Authority: \"td-token\", // matches bootstrap credentials\n}","handlingStrategy":"retry","validationCode":"// Pre-check reachability before opening the LRS stream.\nfunc lrsReachable(ctx context.Context, si clients.ServerIdentifier) error {\n    host, port, err := net.SplitHostPort(si.ServerURI)\n    if err != nil { return err }\n    d := net.Dialer{Timeout: 3 * time.Second}\n    conn, err := d.DialContext(ctx, \"tcp\", net.JoinHostPort(host, port))\n    if err != nil { return err }\n    conn.Close()\n    return nil\n}","typeGuard":null,"tryCatchPattern":"// The LRS client already retries internally; treat ReportLoad errors as\n// transient and back off yourself if you drive reconnection.\nls, err := client.ReportLoad(si)\nif err != nil {\n    logger.Warnf(\"LRS unavailable, will retry: %v\", err)\n    return\n}","preventionTips":["Validate ServerIdentifier URI and credentials in the TransportBuilder before calling ReportLoad.","Treat first-response errors as transient; the runner applies exponential backoff automatically.","Monitor for sustained failure rather than a single occurrence."],"tags":["grpc","xds","lrs","network","streaming"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}