{"record":{"id":"e88afdba4166bebe","repo":"grpc/grpc-go","slug":"endpoints-list-contains-no-addresses","errorCode":null,"errorMessage":"endpoints list contains no addresses","messagePattern":"endpoints list contains no addresses","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"resolver/resolver.go","lineNumber":358,"sourceCode":"\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":340,"sourceCodeEnd":360,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/resolver/resolver.go#L340-L360","documentation":"Returned by resolver.ValidateEndpoints when the endpoints slice is non-empty but every Endpoint in it has an empty Addresses slice. The dual-stack/petiole logic needs at least one dialable address; endpoints with no addresses are not usable and the validation fails.","triggerScenarios":"Calling ValidateEndpoints with a list of Endpoint structs whose Addresses field is nil or [] for all entries. Each iteration of the inner loop `for range endpoint.Addresses` returns immediately, so the function falls through to the error.","commonSituations":"EDS/xDS update carries localities but each locality's endpoints were stripped of addresses by a buggy filter. Custom resolver populates metadata but not Addresses. A proto conversion dropped the address field during a version upgrade.","solutions":["Ensure each Endpoint has at least one Address (host:port) before calling ValidateEndpoints; filter out address-less endpoints upstream.","Check the resolver producing the Endpoint list: confirm it copies socket_addresses into Endpoint.Addresses.","If the source genuinely has no addresses yet (e.g. DNS returned CNAME only), surface a transient error rather than a finalized empty-address list."],"exampleFix":"// before\neps := []resolver.Endpoint{ {HealthStatus: ...} } // Addresses nil\nresolver.ValidateEndpoints(eps)\n// after\neps := []resolver.Endpoint{ { Addresses: []resolver.Address{{Addr: \"10.0.0.1:8080\"}} } }\nresolver.ValidateEndpoints(eps)","handlingStrategy":"validation","validationCode":"// Filter out address-less endpoints before validation.\nfunc withAddressesOnly(eps []resolver.Endpoint) []resolver.Endpoint {\n    out := eps[:0]\n    for _, e := range eps { if len(e.Addresses) > 0 { out = append(out, e) } }\n    return out\n}","typeGuard":"func endpointsHaveAddresses(eps []resolver.Endpoint) bool {\n    for _, e := range eps { if len(e.Addresses) > 0 { return true } }\n    return false\n}","tryCatchPattern":"if err := resolver.ValidateEndpoints(eps); err != nil { if strings.Contains(err.Error(), \"no addresses\") { /* keep previous picker; log transient */ return } return err }","preventionTips":["In resolver implementations, drop endpoints with empty Addresses before producing the update.","Validate proto-to-resolver.Endpoint conversion covers the socket_addresses field.","Add test coverage for EDS responses with localities but no endpoints."],"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"}