#9409·grpc-go

Disallow endpoints with zero addresses

Author: easwarsCreated Sep 10, 2026Updated Sep 14, 2026
LabelsStatus: Help WantedP2Type: Bug

Use case(s) - what problem will this feature solve?

During the investigation of #9259, where randomsubsetting panicked when receiving an endpoint with zero addresses (len(endpoint.Addresses) == 0), we noticed that our codebase does not consistently validate, filter, or handle endpoints with zero addresses:

  1. resolver.ValidateEndpoints has no callers and permits empty endpoints:

    • resolver.ValidateEndpoints was added per gRFC A61 for petiole policies, but currently has zero callers across the repository.
    • In addition, resolver.ValidateEndpoints only checks that the entire list contains at least one address across all endpoints; it does not validate that individual endpoints have at least one address.
  2. Channel / resolver wrapper performs no validation:

    • resolver_wrapper.go passes ResolverState.Endpoints directly to the balancer without validating that endpoints contain addresses.
  3. Inconsistent balancer handling:

    • randomsubsetting recently added explicit filtering in #9259 to avoid an out-of-bounds panic when indexing endpoint.Addresses[0].
    • endpointsharding originally had if len(endpoint.Addresses) == 0 { continue } (added in #7674), but this check was inadvertently removed during the WRR refactoring (#7826). Currently, an empty endpoint creates a child balancer with resolver.State{Endpoints: []resolver.Endpoint{emptyEndpoint}}.
    • While pickfirst flattens endpoint.Addresses... (which simply skips empty endpoints), other balancers or custom petiole policies may assume len(endpoint.Addresses) > 0.
  4. xDS EDS unmarshaling produces dummy ":0" addresses:

    • In unmarshal_eds.go, parseAddress(lbEndpoint.GetEndpoint().GetAddress().GetSocketAddress()) does not validate that the socket address is present. If missing, parseAddress(nil) produces ":0", synthesizing an endpoint with address ":0" instead of NACKing or dropping the endpoint. (If multiple endpoints lack an address, it only NACKs due to duplicate address collision on ":0").
      • Check the implementation in C++ and Java to see what their behavior is before deciding on our behavior.

Proposed Solution

  1. Clarify the contract: A resolver.Endpoint must contain at least one address.
    • Update resolver.ValidateEndpoints (or channel/resolver wrapper) to validate that every endpoint has at least one address.
    • Wire up resolver.ValidateEndpoints in petiole policies and/or resolver_wrapper.
    • In xDS client EDS parsing, validate that a socket address is present (or reject/NACK appropriately).
  2. Go a step further: Explore the option specified in this comment.

Additional Context