grpc/grpc-go · error

xds_wrr_locality: missing locality weight information in…

Error message

xds_wrr_locality: missing locality weight information in endpoint %q

What it means

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.

Solutions

  1. Only deploy the wrr_locality balancer behind the xDS resolver (target scheme xds:///) so endpoints arrive with LocalityWeight attached.
  2. If you build a custom resolver feeding this balancer, attach weights with wrrlocality.SetAddrInfo(endpoint, wrrlocality.AddrInfo{LocalityWeight: w}) for every endpoint.
  3. Verify the cluster is EDS-enabled in the control plane so locality weights are populated.
  4. Check for regressions in your gRPC version's xDS resolver EDS handling.

Example fix

// before: custom resolver emits endpoints without weight
ep := resolver.Endpoint{Addresses: addrs}

// after: attach locality weight before returning endpoints
import "google.golang.org/grpc/internal/xds/balancer/wrrlocality"
ep := wrrlocality.SetAddrInfo(resolver.Endpoint{Addresses: addrs}, wrrlocality.AddrInfo{LocalityWeight: 100})
Defensive patterns

Strategy: validation

Validate before calling

// Ensure every endpoint carries LocalityWeight before updating the balancer.
func ensureAddrInfo(eps []resolver.Endpoint) error {
    for _, ep := range eps {
        if _, ok := wrrlocality.AddrInfo{}.Equal; ok; _ = ok {
        }
        // Use the package helper: read the attribute directly.
        v := ep.Attributes.Value(attributeKey{})
        if _, ok := v.(wrrlocality.AddrInfo); !ok {
            return fmt.Errorf("endpoint missing locality weight: %v", ep)
        }
    }
    return nil
}

Type guard

// Type guard for the AddrInfo attribute value.
func asAddrInfo(v any) (wrrlocality.AddrInfo, bool) {
    ai, ok := v.(wrrlocality.AddrInfo)
    return ai, ok
}

Try / catch

// UpdateClientConnState returns the error; surface it from your balancer wrapper.
if err := b.UpdateClientConnState(s); err != nil {
    if strings.Contains(err.Error(), "missing locality weight") {
        // endpoints were not produced by the xDS resolver; switch balancer or fix resolver.
    }
    return err
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11). Data as JSON: /api/errors/d48f695305c7d713. Report an issue: GitHub.

Appendix: source

Thrown at internal/xds/balancer/wrrlocality/balancer.go:170

}

func (b *wrrLocalityBalancer) UpdateClientConnState(s balancer.ClientConnState) error {
	lbCfg, ok := s.BalancerConfig.(*LBConfig)
	if !ok {
		b.logger.Errorf("Received config with unexpected type %T: %v", s.BalancerConfig, s.BalancerConfig)
		return balancer.ErrBadResolverState
	}

	weightedTargets := make(map[string]weightedtarget.Target)
	for _, ep := range s.ResolverState.Endpoints {
		// This get of LocalityID could potentially return a zero value. This
		// shouldn't happen though (this attribute that is set actually gets
		// used to build localities in the first place), and thus don't error
		// out, and just build a weighted target with undefined behavior.
		locality := xdsinternal.LocalityString(xdsinternal.LocalityIDFromEndpoint(ep))
		ai, ok := getAddrInfo(ep)
		if !ok {
			return fmt.Errorf("xds_wrr_locality: missing locality weight information in endpoint %q", ep)
		}
		weightedTargets[locality] = weightedtarget.Target{Weight: ai.LocalityWeight, ChildPolicy: lbCfg.ChildPolicy}
	}
	wtCfg := &weightedtarget.LBConfig{Targets: weightedTargets}
	wtCfgJSON, err := json.Marshal(wtCfg)
	if err != nil {
		// Shouldn't happen.
		return fmt.Errorf("xds_wrr_locality: error marshalling prepared config: %v", wtCfg)
	}
	var sc serviceconfig.LoadBalancingConfig
	if sc, err = b.childParser.ParseConfig(wtCfgJSON); err != nil {
		return fmt.Errorf("xds_wrr_locality: config generated %v is invalid: %v", wtCfgJSON, err)
	}

	return b.child.UpdateClientConnState(balancer.ClientConnState{
		ResolverState:  s.ResolverState,
		BalancerConfig: sc,
	})

View on GitHub (pinned to 0c51461d27)