grpc/grpc-go · error

rls: invalid childPolicy config: no supported policies…

Error message

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

What it means

Emitted from parseChildPolicyConfigs (config.go:322) after iterating every childPolicy entry without finding one whose name is a registered balancer (balancer.Get returns non-nil). Unregistered names are skipped silently during iteration; the error fires only if none of the listed policies are registered in this binary.

Solutions

  1. Use a definitely-registered policy such as 'round_robin' or 'pick_first' (imported via the core grpc module).
  2. Blank-import the package providing the desired child policy, e.g. _ 'google.golang.org/grpc/balancer/roundrobin' or the xds module for cds/xds_cluster_resolver.
  3. Check the spelling against balancer.Get(name) in a tiny test program; nil means not registered.
  4. If multiple candidates are listed, ensure at least one is registered; ordering only affects which one wins, not whether this error fires.

Example fix

// before: misspelled / unregistered policy
"childPolicy": [ { "roundrobin": {} } ]

// after
"childPolicy": [ { "round_robin": {} } ]
// and if needed in the binary:
import _ "google.golang.org/grpc/balancer/roundrobin"
Defensive patterns

Strategy: validation

Validate before calling

func anyChildPolicyRegistered(policies []map[string]json.RawMessage) error {
    found := false
    for _, e := range policies {
        for name := range e {
            if balancer.Get(name) != nil {
                found = true
            }
        }
    }
    if !found {
        return errors.New("no registered balancer found among childPolicy entries")
    }
    return nil
}

Type guard

func childPolicyIsRegistered(name string) bool { return balancer.Get(name) != nil }

Prevention

When it happens

Trigger: Every policy name in the childPolicy array is either misspelled or refers to a balancer whose package is not linked into the binary. balancer.Get returns nil for each, so the loop completes without selecting one.

Common situations: Typo in policy name (e.g. 'roundrobin' instead of 'round_robin', 'grpclb' on a build without grpclb); using xDS child policies (cds, xds_cluster_resolver) in a non-xDS binary that does not import them; a custom LB not blank-imported; relying on an LB registered by a plugin that is disabled in this build.

Related errors


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

Appendix: 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 0c51461d27)