grpc/grpc-go · warning
unexpected message type %T
Error message
unexpected message type %T
What it means
Returned by adsStreamImpl.recvMessage when proto.Unmarshal of the received bytes into DiscoveryResponse fails (ads_stream.go:495). As with the LRS variant, the error is reported as an unexpected message type even though the real cause is a protobuf deserialization failure.
Solutions
- Verify the management server implements the v3 xDS protocol (envoy.service.discovery.v3.AggregatedDiscoveryService).
- Point the bootstrap xds_server.uri at a real xDS endpoint.
- Increase logging verbosity to capture the raw bytes and confirm a version mismatch.
- If a v2 server is unavoidable, use a client version that supports v2 or deploy a v2-to-v3 translating control plane.
Defensive patterns
Strategy: retry
Prevention
- Point the bootstrap xds_server at a v3-capable management server.
- Verify the endpoint with grpcurl listing the ADS service.
- The ADS runner reconnects with backoff automatically - no caller action needed for transient cases.
When it happens
Trigger: On the ADS stream, stream.Recv() returns bytes that do not unmarshal as envoy.service.discovery.v3.DiscoveryResponse. recv returns this error and the recv loop treats it as a stream failure, triggers onError, and reconnects with backoff.
Common situations: xDS server speaks v2 (envoy.api.v2.DiscoveryResponse) while client expects v3; server is not actually an xDS management server; proxy corrupted the frame; version skew between client and control plane.
Related errors
- lrs: unexpected message type %T
- extauthz: failed to unmarshal config
- extauthz: failed to unmarshal override config
- extproc: failed to unmarshal config
- extproc: failed to unmarshal override
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/de936816f646bb8b.
Report an issue: GitHub.
Appendix: source
Thrown at internal/xds/clients/xdsclient/ads_stream.go:495
// know that it's invalid. But we shouldn't ACK either, because we
// don't know that it is valid.
s.logger.Warningf("%v", nackErr)
continue
}
s.onRecv(stream, resourceNames, url, version, nonce, nackErr)
}
}
func (s *adsStreamImpl) recvMessage(stream clients.Stream) (resources []*anypb.Any, url, version, nonce string, err error) {
r, err := stream.Recv()
if err != nil {
return nil, "", "", "", err
}
var resp v3discoverypb.DiscoveryResponse
if err := proto.Unmarshal(r, &resp); err != nil {
s.logger.Infof("Failed to unmarshal response to DiscoveryResponse: %v", err)
return nil, "", "", "", fmt.Errorf("unexpected message type %T", r)
}
if s.logger.V(perRPCVerbosityLevel) {
s.logger.Infof("ADS response received: %v", pretty.ToJSON(&resp))
} else if s.logger.V(2) {
s.logger.Infof("ADS response received for type %q, version %q, nonce %q", resp.GetTypeUrl(), resp.GetVersionInfo(), resp.GetNonce())
}
return resp.GetResources(), resp.GetTypeUrl(), resp.GetVersionInfo(), resp.GetNonce(), nil
}
// onRecv is invoked when a response is received from the server. The arguments
// passed to this method correspond to the most recently received response.
//
// It performs the following actions:
// - updates resource type specific state
// - updates resource specific state for resources in the response
// - sends an ACK or NACK to the server based on the response
func (s *adsStreamImpl) onRecv(stream clients.Stream, names []string, url, version, nonce string, nackErr error) {
s.mu.Lock()View on GitHub (pinned to 0c51461d27)