grpc/grpc-go · warning

lrs: unexpected message type %T

Error message

lrs: unexpected message type %T

What it means

Returned by recvFirstLoadStatsResponse when the bytes received from the server cannot be unmarshaled into a LoadStatsResponse (lrs_stream.go:214). The implementation reports this as an unexpected message type even though the root cause is a protobuf unmarshal failure.

Solutions

  1. Confirm both client and server implement the v3 LRS service (envoy.service.load_stats.v3).
  2. Capture traffic (or raise perRPCVerbosityLevel logging) to inspect the actual bytes received.
  3. Point the client at the correct LRS endpoint/method.
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: stream.Recv() succeeds but proto.Unmarshal(r, &v3lrspb.LoadStatsResponse{}) fails - typically because the server sent a v2 message, a wrong-type response, or corrupted bytes. The function then returns fmt.Errorf("lrs: unexpected message type %T", r).

Common situations: Server and client disagree on the LRS proto version (v2 vs v3); the endpoint is not actually LRS (e.g. it returned a DiscoveryResponse); a buggy server serializes the wrong message type on the StreamLoadStats method.

Related errors


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

Appendix: source

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

}

// 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()

	clusters := resp.Clusters
	if resp.SendAllClusters {
		// Return an empty slice to send stats for all clusters.
		clusters = []string{}
	}

	return clusters, loadReportingInterval, nil

View on GitHub (pinned to 0c51461d27)