{"record":{"id":"8ebb502d998106e0","repo":"grpc/grpc-go","slug":"endpoints-list-is-empty","errorCode":null,"errorMessage":"endpoints list is empty","messagePattern":"endpoints list is empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"resolver/resolver.go","lineNumber":350,"sourceCode":"type AuthorityOverrider interface {\n\t// OverrideAuthority returns the authority to use for a ClientConn with the\n\t// given target. The implementation must generate it without blocking,\n\t// typically in line, and must keep it unchanged.\n\t//\n\t// The returned string must be a valid \":authority\" header value, i.e. be\n\t// encoded according to\n\t// [RFC3986](https://datatracker.ietf.org/doc/html/rfc3986#section-3.2) as\n\t// necessary.\n\tOverrideAuthority(Target) string\n}\n\n// ValidateEndpoints validates endpoints from a petiole policy's perspective.\n// Petiole policies should call this before calling into their children. See\n// [gRPC A61](https://github.com/grpc/proposal/blob/master/A61-IPv4-IPv6-dualstack-backends.md)\n// for details.\nfunc ValidateEndpoints(endpoints []Endpoint) error {\n\tif len(endpoints) == 0 {\n\t\treturn errors.New(\"endpoints list is empty\")\n\t}\n\n\tfor _, endpoint := range endpoints {\n\t\tfor range endpoint.Addresses {\n\t\t\treturn nil\n\t\t}\n\t}\n\treturn errors.New(\"endpoints list contains no addresses\")\n}\n","sourceCodeStart":332,"sourceCodeEnd":360,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/resolver/resolver.go#L332-L360","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nfunc buildAddrs(eps []resolver.Endpoint) []resolver.Address {\n    _ = resolver.ValidateEndpoints(eps) // errors when eps is empty\n    ...\n}\n// after\nfunc buildAddrs(eps []resolver.Endpoint) ([]resolver.Address, error) {\n    if err := resolver.ValidateEndpoints(eps); err != nil { return nil, err }\n    ...\n}","handlingStrategy":"validation","validationCode":"// Validate before producing a resolver update.\nif len(eps) == 0 {\n    // Optionally surface an error state instead of an empty update.\n    return fmt.Errorf(\"no endpoints available for %s\", target)\n}","typeGuard":"func hasEndpoints(eps []resolver.Endpoint) bool { return len(eps) > 0 }","tryCatchPattern":"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 }","preventionTips":["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."],"tags":["resolver","endpoints","petiole","dualstack","load-balancing"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}