grpc/grpc-go · warning

lrs: failed to receive first LoadStatsResponse

Error message

lrs: failed to receive first LoadStatsResponse: %v

What it means

Returned by recvFirstLoadStatsResponse when the first stream.Recv() on the LRS stream fails (lrs_stream.go:207). The runner logs it as a warning and retries with backoff, so this is a transient/recoverable condition rather than a fatal one.

Solutions

  1. Check connectivity and TLS to the LRS server independently (grpcurl, openssl s_client).
  2. Confirm the target URI is an LRS-enabled endpoint (envoy.service.load_stats.v3.LoadReportingService).
  3. Raise gRPC verbosity to see the wrapped transport error and act on it.
  4. If transient, rely on the built-in exponential backoff - the runner will reconnect automatically.
Defensive patterns

Strategy: retry

Prevention

When it happens

Trigger: The LRS server closes the StreamLoadStats stream before sending any LoadStatsResponse, or the underlying transport fails (TLS error, RST_STREAM, context cancel, deadline). The first Recv after sending the initial LoadStatsRequest returns a non-nil error.

Common situations: LRS server is not actually an LRS server (wrong URI); server rejects the node identity; TLS handshake to the LRS server fails; intermediate proxy times out idle streams; server-side bug drops the stream on first message.

Related errors


AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11). Data as JSON: /api/errors/036e7efe17671af4. Report an issue: GitHub.

Appendix: source

Thrown at internal/xds/clients/lrsclient/lrs_stream.go:207

		return err
	}
	err = stream.Send(msg)
	if err == io.EOF {
		return getStreamError(stream)
	}
	return err
}

// recvFirstLoadStatsResponse receives the first LoadStatsResponse from the LRS
// server.  Returns the following:
//   - a list of cluster names requested by the server or an empty slice if the
//     server requested for load from all clusters
//   - the load reporting interval, and
//   - any error encountered
func (lrs *streamImpl) recvFirstLoadStatsResponse(stream clients.Stream) ([]string, time.Duration, error) {
	r, err := stream.Recv()
	if err != nil {
		return nil, 0, fmt.Errorf("lrs: failed to receive first LoadStatsResponse: %v", err)
	}
	var resp v3lrspb.LoadStatsResponse
	if err := proto.Unmarshal(r, &resp); err != nil {
		if lrs.logger.V(2) {
			lrs.logger.Infof("Failed to unmarshal response to LoadStatsResponse: %v", err)
		}
		return nil, time.Duration(0), fmt.Errorf("lrs: unexpected message type %T", r)
	}
	if lrs.logger.V(perRPCVerbosityLevel) {
		lrs.logger.Infof("Received first LoadStatsResponse: %s", pretty.ToJSON(&resp))
	}

	internal := resp.GetLoadReportingInterval()
	if internal.CheckValid() != nil {
		return nil, 0, fmt.Errorf("lrs: invalid load_reporting_interval: %v", err)
	}
	loadReportingInterval := internal.AsDuration()

View on GitHub (pinned to 0c51461d27)