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
- Use a registered policy name such as "round_robin", "pick_first", or "weighted_round_robin".
- If using a custom balancer, ensure its package is imported for side effects (blank import) so balancer.Register runs before config parse.
- 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
- Use lowercase canonical policy names (round_robin, pick_first).
- Blank-import custom balancer packages so registration init() runs.
- Never leave childPolicy empty in an RLS config.
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
- rls: invalid childPolicy: entry %v does not contain exactly
- rls: childPolicy %q with config %q does not support config p
- rls: childPolicy config validation failed: %v
- rls: stale_age is set, but max_age is not in route lookup co
- rls: cache_size_bytes must be set to a non-zero value: %+v
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/a7df519388f60fe4.
Report an issue: GitHub.