grpc/grpc-go · error

rls: invalid childPolicy config: no supported policies found

Error message

rls: invalid childPolicy config: no supported policies found in %+v

What it means

parseChildPolicyConfigs iterates the childPolicy list and skips any entry whose name is not a registered balancer (balancer.Get returns nil). If none of the entries resolve to a registered builder, RLS has no valid child to delegate to and rejects the whole config. This also fires when the list is empty.

Source

Thrown at balancer/rls/config.go:322

		// - 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)
		}
		return name, childConfig, nil
	}
	return "", nil, fmt.Errorf("rls: invalid childPolicy config: no supported policies found in %+v", childPolicies)
}

func convertDuration(d *durationpb.Duration) (time.Duration, error) {
	if d == nil {
		return 0, nil
	}
	return d.AsDuration(), d.CheckValid()
}

View on GitHub (pinned to 03255a9237)

Solutions

  1. Use a registered policy name such as "round_robin", "pick_first", or "weighted_round_robin".
  2. If using a custom balancer, ensure its package is imported for side effects (blank import) so balancer.Register runs before config parse.
  3. Provide at least one childPolicy entry — the list must not be empty.

Example fix

// before
"childPolicy": [{ "RoundRobin": {} }]
// after
"childPolicy": [{ "round_robin": {} }]
Defensive patterns

Strategy: validation

Validate before calling

func validateAtLeastOneRegisteredChild(childPolicy []map[string]json.RawMessage) error {
    for _, entry := range childPolicy {
        for name := range entry {
            if balancer.Get(name) != nil {
                return nil
            }
        }
    }
    return fmt.Errorf("no registered child policy found")
}

Prevention

When it happens

Trigger: Every name in childPolicy is misspelled or unregistered (e.g. "RoundRobin" instead of "round_robin", or a custom LB not yet balancer.Register'd); or childPolicy is an empty array.

Common situations: Wrong policy name casing; referencing a balancer from an not-yet-imported package (its init() never ran); xDS producing a child policy list with names the client doesn't know; blank childPolicy.

Related errors


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/a7df519388f60fe4. Report an issue: GitHub.