vitessio/vitess · error

unsupported balancer policy %s; must be one of %s

Error message

unsupported balancer policy %s; must be one of %s

What it means

BalancerPolicy implements pflag.Value; Set validates the string and rejects anything other than the registered policies (pickfirst or round_robin). The error lists the valid options via allBalancerPolicies. It is thrown at flag/config parsing time, before any gRPC connection is attempted, so the process fails fast with an actionable message.

Source

Thrown at go/vt/vtadmin/cluster/resolver/resolver.go:98

const (
	// PickFirstBalancer
	PickFirstBalancer  BalancerPolicy = "pick_first"
	RoundRobinBalancer BalancerPolicy = "round_robin"
)

var allBalancerPolicies = []string{ // convenience for help/error messages
	string(PickFirstBalancer),
	string(RoundRobinBalancer),
}

// Set is part of the pflag.Value interface.
func (bp *BalancerPolicy) Set(s string) error {
	switch s {
	case string(PickFirstBalancer), string(RoundRobinBalancer):
		*bp = BalancerPolicy(s)
	default:
		return fmt.Errorf("unsupported balancer policy %s; must be one of %s", s, strings.Join(allBalancerPolicies, ", "))
	}

	return nil
}

// String is part of the pflag.Value interface.
func (bp *BalancerPolicy) String() string { return string(*bp) }

// Type is part of the pflag.Value interface.
func (*BalancerPolicy) Type() string { return "resolver.BalancerPolicy" }

// Options defines the configuration options that can produce a resolver.Builder.
//
// A builder may be produced directly from an Options struct, but the intended
// usage is to first initialize an Options struct via opts.InstallFlags, which
// ensures the Options have sensible defaults and both vtctldclient proxy and
// VTGateProxy do.
type Options struct {

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Use exactly one of the supported values listed in the error (pickfirst or round_robin).
  2. Check strings.Join(allBalancerPolicies, ", ") output / resolver source for canonical casing.
  3. Remove the policy setting entirely to fall back to gRPC's default balancer.
  4. If another policy is needed, register it in the resolver before use (code change).

Example fix

// before
bp.Set("round-robin")
// after
bp.Set("round_robin")
Defensive patterns

Strategy: validation

Validate before calling

func validBalancerPolicy(s string) bool {
  return s == string(resolver.PickFirstBalancer) || s == string(resolver.RoundRobinBalancer)
}
if !validBalancerPolicy(policy) {
  return fmt.Errorf("policy %q unsupported", policy)
}

Type guard

func isBalancerPolicy(s string) (resolver.BalancerPolicy, bool) {
  bp := resolver.BalancerPolicy(s)
  return bp, bp.Set(s) == nil
}

Try / catch

bp := resolver.BalancerPolicy(cfg.Policy)
if err := bp.Set(cfg.Policy); err != nil {
  log.Warn("falling back to default balancer", slog.Any("error", err))
  bp = ""
}

Prevention

When it happens

Trigger: Passing --grpc-resolver-balancer-policy (or setting BalancerPolicy via config/API) with a value like "roundrobin", "least_request", or a misspelled policy to resolver BalancerPolicy.Set, or embedding it in a cluster config that is unmarshaled through the flag interface.

Common situations: Developers copying gRPC load-balancing policy names from general gRPC docs (e.g. 'ring_hash', 'weighted_target') that this resolver does not register; typos like 'round-robin' vs the exact registered string.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/46f87fadeb457bd1. Report an issue: GitHub.