grpc/grpc-go · error

rls: childPolicy with config does not support config parsing

Error message

rls: childPolicy %q with config %q does not support config parsing

What it means

Emitted from parseChildPolicyConfigs (config.go:300) when the balancer.Builder registered under the child-policy name does not implement the balancer.ConfigParser interface. The RLS balancer must parse and validate the child policy config (to inject the target field), so a builder that exposes no ConfigParser is unusable as an RLS child.

Solutions

  1. Switch the childPolicy to a balancer that implements ConfigParser (round_robin, weighted_round_robin, cds, xds_cluster_resolver, etc.).
  2. If you maintain the child balancer, implement balancer.ConfigParser (ParseConfig(json.RawMessage) (LoadBalancingConfig, error)) on its builder.
  3. Reorder the childPolicy array so a parser-supporting policy is listed first if you must keep the non-parser one as a fallback name (it will be skipped, not error, only if it is not the first registered).

Example fix

// before: 'custom_lb' builder has no ConfigParser
"childPolicy": [ { "custom_lb": {} } ]

// after: use a balancer that supports config parsing
"childPolicy": [ { "round_robin": {} } ]
// or implement on custom_lb:
// func (b *customLBBuilder) ParseConfig(raw json.RawMessage) (serviceconfig.LoadBalancingConfig, error) { ... }
Defensive patterns

Strategy: type-guard

Validate before calling

func childPolicySupportsParsing(name string) bool {
    b := balancer.Get(name)
    if b == nil {
        return false
    }
    _, ok := b.(balancer.ConfigParser)
    return ok
}

Type guard

func isConfigParser(b balancer.Builder) bool {
    _, ok := b.(balancer.ConfigParser)
    return ok
}

Prevention

When it happens

Trigger: A childPolicy entry names a registered balancer whose Builder type does not satisfy balancer.ConfigParser (no ParseConfig method). The entry is the first registered builder encountered, so the error is immediate rather than skipped.

Common situations: Using a minimal/custom balancer that was registered with balancer.Register but whose author did not implement ConfigParser; using the legacy 'pick_first'/'round_robin' from a very old or forked module where the parser interface was not implemented; a balancer that is config-less by design.

Related errors


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

Appendix: source

Thrown at balancer/rls/config.go:300

// parseChildPolicyConfigs iterates through the list of child policies and picks
// the first registered policy and validates its config.
func parseChildPolicyConfigs(childPolicies []map[string]json.RawMessage, targetFieldName string) (string, map[string]json.RawMessage, error) {
	for i, config := range childPolicies {
		if len(config) != 1 {
			return "", nil, fmt.Errorf("rls: invalid childPolicy: entry %v does not contain exactly 1 policy/config pair: %q", i, config)
		}

		var name string
		var rawCfg json.RawMessage
		for name, rawCfg = range config {
		}
		builder := balancer.Get(name)
		if builder == nil {
			continue
		}
		parser, ok := builder.(balancer.ConfigParser)
		if !ok {
			return "", nil, fmt.Errorf("rls: childPolicy %q with config %q does not support config parsing", name, string(rawCfg))
		}

		// To validate child policy configs we do the following:
		// - unmarshal the raw JSON bytes of the child policy config into a map
		// - add an entry with key set to `target_field_name` and a dummy value
		// - marshal the map back to JSON and parse the config using the parser
		// retrieved previously
		var childConfig map[string]json.RawMessage
		if err := json.Unmarshal(rawCfg, &childConfig); err != nil {
			return "", nil, fmt.Errorf("rls: json unmarshal failed for child policy config %q: %v", string(rawCfg), err)
		}
		childConfig[targetFieldName], _ = json.Marshal(dummyChildPolicyTarget)
		jsonCfg, err := json.Marshal(childConfig)
		if err != nil {
			return "", nil, fmt.Errorf("rls: json marshal failed for child policy config {%+v}: %v", childConfig, err)
		}
		if _, err := parser.ParseConfig(jsonCfg); err != nil {
			return "", nil, fmt.Errorf("rls: childPolicy config validation failed: %v", err)

View on GitHub (pinned to 0c51461d27)