{"record":{"id":"d48f695305c7d713","repo":"grpc/grpc-go","slug":"xds-wrr-locality-missing-locality-weight-informat","errorCode":null,"errorMessage":"xds_wrr_locality: missing locality weight information in endpoint %q","messagePattern":"xds_wrr_locality: missing locality weight information in endpoint %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/balancer/wrrlocality/balancer.go","lineNumber":170,"sourceCode":"}\n\nfunc (b *wrrLocalityBalancer) UpdateClientConnState(s balancer.ClientConnState) error {\n\tlbCfg, ok := s.BalancerConfig.(*LBConfig)\n\tif !ok {\n\t\tb.logger.Errorf(\"Received config with unexpected type %T: %v\", s.BalancerConfig, s.BalancerConfig)\n\t\treturn balancer.ErrBadResolverState\n\t}\n\n\tweightedTargets := make(map[string]weightedtarget.Target)\n\tfor _, ep := range s.ResolverState.Endpoints {\n\t\t// This get of LocalityID could potentially return a zero value. This\n\t\t// shouldn't happen though (this attribute that is set actually gets\n\t\t// used to build localities in the first place), and thus don't error\n\t\t// out, and just build a weighted target with undefined behavior.\n\t\tlocality := xdsinternal.LocalityString(xdsinternal.LocalityIDFromEndpoint(ep))\n\t\tai, ok := getAddrInfo(ep)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"xds_wrr_locality: missing locality weight information in endpoint %q\", ep)\n\t\t}\n\t\tweightedTargets[locality] = weightedtarget.Target{Weight: ai.LocalityWeight, ChildPolicy: lbCfg.ChildPolicy}\n\t}\n\twtCfg := &weightedtarget.LBConfig{Targets: weightedTargets}\n\twtCfgJSON, err := json.Marshal(wtCfg)\n\tif err != nil {\n\t\t// Shouldn't happen.\n\t\treturn fmt.Errorf(\"xds_wrr_locality: error marshalling prepared config: %v\", wtCfg)\n\t}\n\tvar sc serviceconfig.LoadBalancingConfig\n\tif sc, err = b.childParser.ParseConfig(wtCfgJSON); err != nil {\n\t\treturn fmt.Errorf(\"xds_wrr_locality: config generated %v is invalid: %v\", wtCfgJSON, err)\n\t}\n\n\treturn b.child.UpdateClientConnState(balancer.ClientConnState{\n\t\tResolverState:  s.ResolverState,\n\t\tBalancerConfig: sc,\n\t})","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/xds/balancer/wrrlocality/balancer.go#L152-L188","documentation":"Thrown by wrr_locality's UpdateClientConnState when an endpoint received from the resolver does not carry the AddrInfo attribute (LocalityWeight). The xDS resolver is supposed to attach LocalityWeight to each endpoint via SetAddrInfo when processing EDS results; if it is absent the balancer cannot build weighted targets.","triggerScenarios":"Triggered at balancer.go:170 when getAddrInfo(ep) returns ok==false for any endpoint in s.ResolverState.Endpoints. Happens when the upstream resolver did not call SetAddrInfo (e.g. endpoints originated from a non-xDS resolver or an EDS path that skips locality weighting).","commonSituations":"Using the xds_wrr_locality_experimental balancer outside of an xds:/// resolved channel; a bug or partial regression in the xDS resolver that fails to set AddrInfo; mixing endpoints from a custom resolver with the xDS balancer.","solutions":["Only deploy the wrr_locality balancer behind the xDS resolver (target scheme xds:///) so endpoints arrive with LocalityWeight attached.","If you build a custom resolver feeding this balancer, attach weights with wrrlocality.SetAddrInfo(endpoint, wrrlocality.AddrInfo{LocalityWeight: w}) for every endpoint.","Verify the cluster is EDS-enabled in the control plane so locality weights are populated.","Check for regressions in your gRPC version's xDS resolver EDS handling."],"exampleFix":"// before: custom resolver emits endpoints without weight\nep := resolver.Endpoint{Addresses: addrs}\n\n// after: attach locality weight before returning endpoints\nimport \"google.golang.org/grpc/internal/xds/balancer/wrrlocality\"\nep := wrrlocality.SetAddrInfo(resolver.Endpoint{Addresses: addrs}, wrrlocality.AddrInfo{LocalityWeight: 100})","handlingStrategy":"validation","validationCode":"// Ensure every endpoint carries LocalityWeight before updating the balancer.\nfunc ensureAddrInfo(eps []resolver.Endpoint) error {\n    for _, ep := range eps {\n        if _, ok := wrrlocality.AddrInfo{}.Equal; ok; _ = ok {\n        }\n        // Use the package helper: read the attribute directly.\n        v := ep.Attributes.Value(attributeKey{})\n        if _, ok := v.(wrrlocality.AddrInfo); !ok {\n            return fmt.Errorf(\"endpoint missing locality weight: %v\", ep)\n        }\n    }\n    return nil\n}","typeGuard":"// Type guard for the AddrInfo attribute value.\nfunc asAddrInfo(v any) (wrrlocality.AddrInfo, bool) {\n    ai, ok := v.(wrrlocality.AddrInfo)\n    return ai, ok\n}","tryCatchPattern":"// UpdateClientConnState returns the error; surface it from your balancer wrapper.\nif err := b.UpdateClientConnState(s); err != nil {\n    if strings.Contains(err.Error(), \"missing locality weight\") {\n        // endpoints were not produced by the xDS resolver; switch balancer or fix resolver.\n    }\n    return err\n}","preventionTips":["Only use xds_wrr_locality_experimental with the xDS resolver (xds:/// target).","If feeding endpoints from a custom resolver, always call wrrlocality.SetAddrInfo.","In tests, build endpoints with SetAddrInfo to mirror production."],"tags":["grpc","xds","balancer","wrr-locality","endpoints","go"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}