grpc/grpc-go · warning
endpoints list is empty
Error message
endpoints list is empty
What it means
Returned by resolver.ValidateEndpoints when the endpoints slice passed in has length 0. Petiole (dual-stack endpoints, gRFC A61) policies call this to enforce that at least one endpoint exists before delegating to child policies; an empty list means there is nothing to dial.
Solutions
- At the resolver/producer side, skip emitting a resolved address update when endpoints is empty, or send an empty-state error instead of a zero-length list.
- Check the upstream EDS/DNS source: confirm endpoints actually exist and are not filtered out by a health/ locality filter.
Example fix
// before
func buildAddrs(eps []resolver.Endpoint) []resolver.Address {
_ = resolver.ValidateEndpoints(eps) // errors when eps is empty
...
}
// after
func buildAddrs(eps []resolver.Endpoint) ([]resolver.Address, error) {
if err := resolver.ValidateEndpoints(eps); err != nil { return nil, err }
...
} Defensive patterns
Strategy: validation
Validate before calling
// Validate before producing a resolver update.
if len(eps) == 0 {
// Optionally surface an error state instead of an empty update.
return fmt.Errorf("no endpoints available for %s", target)
} Type guard
func hasEndpoints(eps []resolver.Endpoint) bool { return len(eps) > 0 } Try / catch
if err := resolver.ValidateEndpoints(eps); err != nil { if strings.Contains(err.Error(), "empty") { // back off / keep previous addresses rather than flushing the picker return } return err } Prevention
- Resolver implementations should keep the last good address set when a fresh resolution yields zero endpoints.
- Surface transient empty-endpoint states as connection errors, not silent pickers with no addresses.
- Add metrics/alerts for sustained empty-endpoint conditions.
When it happens
Trigger: A resolver or balancer passes an empty []Endpoint slice to ValidateEndpoints. Occurs when an xDS/EDS update removes all endpoints, or when a custom resolver produces an empty list (e.g. DNS returned no records and the resolver propagated that).
Common situations: Endpoint discovery returned zero hosts (scaled to zero, all endpoints evicted). Resolver bug drops endpoints before calling ValidateEndpoints. Transient control-plane state where the cluster has no healthy localities.
Related errors
- endpoints list contains no addresses
- connection active but health check failed. status=
- connection active but received health check RPC error
- could not get resolver for default scheme
- delegating_resolver: failed to determine proxy URL for…
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/8ebb502d998106e0.
Report an issue: GitHub.
Appendix: source
Thrown at resolver/resolver.go:350
type AuthorityOverrider interface {
// OverrideAuthority returns the authority to use for a ClientConn with the
// given target. The implementation must generate it without blocking,
// typically in line, and must keep it unchanged.
//
// The returned string must be a valid ":authority" header value, i.e. be
// encoded according to
// [RFC3986](https://datatracker.ietf.org/doc/html/rfc3986#section-3.2) as
// necessary.
OverrideAuthority(Target) string
}
// ValidateEndpoints validates endpoints from a petiole policy's perspective.
// Petiole policies should call this before calling into their children. See
// [gRPC A61](https://github.com/grpc/proposal/blob/master/A61-IPv4-IPv6-dualstack-backends.md)
// for details.
func ValidateEndpoints(endpoints []Endpoint) error {
if len(endpoints) == 0 {
return errors.New("endpoints list is empty")
}
for _, endpoint := range endpoints {
for range endpoint.Addresses {
return nil
}
}
return errors.New("endpoints list contains no addresses")
}
View on GitHub (pinned to 0c51461d27)