grpc/grpc-go · error

%q LB policy does not implement a config parser

Error message

%q LB policy does not implement a config parser

What it means

Logged and returned as a nop balancer error in bb.Build() (lines 78-79) when the priority balancer builder does not implement the balancer.ConfigParser interface. The CDS balancer needs to parse child policy JSON through this parser; if the type assertion builder.(balancer.ConfigParser) fails, it cannot function. The code comment at line 77 states this should never happen because the imported Priority builder implements ConfigParser.

Source

Thrown at internal/xds/balancer/cdsbalancer/cdsbalancer.go:79

// bb implements the balancer.Builder interface to help build a cdsBalancer.
// It also implements the balancer.ConfigParser interface to help parse the
// JSON service config, to be passed to the cdsBalancer.
type bb struct{}

// Build creates a new CDS balancer with the ClientConn.
func (bb) Build(cc balancer.ClientConn, opts balancer.BuildOptions) balancer.Balancer {
	builder := balancer.Get(priority.Name)
	if builder == nil {
		// Shouldn't happen, registered through imported Priority builder. Still,
		// defensive programming.
		logger.Errorf("%q LB policy is needed but not registered", priority.Name)
		return nop.NewBalancer(cc, fmt.Errorf("%q LB policy is needed but not registered", priority.Name))
	}
	parser, ok := builder.(balancer.ConfigParser)
	if !ok {
		// Shouldn't happen, imported Priority builder has this method.
		logger.Errorf("%q LB policy does not implement a config parser", priority.Name)
		return nop.NewBalancer(cc, fmt.Errorf("%q LB policy does not implement a config parser", priority.Name))
	}

	b := &cdsBalancer{
		bOpts:             opts,
		childConfigParser: parser,
		clusterConfigs:    make(map[string]*xdsresource.ClusterResult),
		priorityConfigs:   make(map[string]*priorityConfig),
		cc:                cc,
	}
	b.logger = prefixLogger(b)
	b.logger.Infof("Created")
	return b
}

// Name returns the name of balancers built by this builder.
func (bb) Name() string {
	return cdsName
}

View on GitHub (pinned to 0c51461d27)

Solutions

  1. Ensure you are using the official grpc-go priority balancer without modifications: check 'go list -m -json google.golang.org/grpc' for the source.
  2. Remove any custom balancer.Register calls that might override the priority.Name registration.
  3. Use the public xds package import rather than internal packages to avoid partial or mismatched registrations.
Defensive patterns

Strategy: type-guard

Validate before calling

// Verify the priority builder implements ConfigParser at startup
func validatePriorityBuilderParser() error {
    b := balancer.Get("priority_experimental")
    if b == nil {
        return fmt.Errorf("priority builder not found")
    }
    if _, ok := b.(balancer.ConfigParser); !ok {
        return fmt.Errorf("priority builder does not implement ConfigParser")
    }
    return nil
}

Type guard

// Type guard for the ConfigParser interface
func isConfigParser(b balancer.Builder) bool {
    _, ok := b.(balancer.ConfigParser)
    return ok
}

Prevention

When it happens

Trigger: balancer.Get(priority.Name) returns a non-nil builder, but that builder does not satisfy balancer.ConfigParser. This would only occur if a different (incorrect) builder was registered under the priority.Name key, or if a fork/modified version of the priority balancer removed the ParseConfig method.

Common situations: A forked or vendored version of the priority balancer that does not implement ConfigParser. A name collision where a custom balancer registers under the same name as the priority balancer. Corruption from inconsistent vendoring.

Related errors


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