{"record":{"id":"71b4fbc2b3992463","repo":"grpc/grpc-go","slug":"rls-childpolicy-q-with-config-q-does-not-suppor","errorCode":null,"errorMessage":"rls: childPolicy %q with config %q does not support config parsing","messagePattern":"rls: childPolicy %q with config %q does not support config parsing","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"balancer/rls/config.go","lineNumber":300,"sourceCode":"// parseChildPolicyConfigs iterates through the list of child policies and picks\n// the first registered policy and validates its config.\nfunc parseChildPolicyConfigs(childPolicies []map[string]json.RawMessage, targetFieldName string) (string, map[string]json.RawMessage, error) {\n\tfor i, config := range childPolicies {\n\t\tif len(config) != 1 {\n\t\t\treturn \"\", nil, fmt.Errorf(\"rls: invalid childPolicy: entry %v does not contain exactly 1 policy/config pair: %q\", i, config)\n\t\t}\n\n\t\tvar name string\n\t\tvar rawCfg json.RawMessage\n\t\tfor name, rawCfg = range config {\n\t\t}\n\t\tbuilder := balancer.Get(name)\n\t\tif builder == nil {\n\t\t\tcontinue\n\t\t}\n\t\tparser, ok := builder.(balancer.ConfigParser)\n\t\tif !ok {\n\t\t\treturn \"\", nil, fmt.Errorf(\"rls: childPolicy %q with config %q does not support config parsing\", name, string(rawCfg))\n\t\t}\n\n\t\t// To validate child policy configs we do the following:\n\t\t// - unmarshal the raw JSON bytes of the child policy config into a map\n\t\t// - add an entry with key set to `target_field_name` and a dummy value\n\t\t// - marshal the map back to JSON and parse the config using the parser\n\t\t// retrieved previously\n\t\tvar childConfig map[string]json.RawMessage\n\t\tif err := json.Unmarshal(rawCfg, &childConfig); err != nil {\n\t\t\treturn \"\", nil, fmt.Errorf(\"rls: json unmarshal failed for child policy config %q: %v\", string(rawCfg), err)\n\t\t}\n\t\tchildConfig[targetFieldName], _ = json.Marshal(dummyChildPolicyTarget)\n\t\tjsonCfg, err := json.Marshal(childConfig)\n\t\tif err != nil {\n\t\t\treturn \"\", nil, fmt.Errorf(\"rls: json marshal failed for child policy config {%+v}: %v\", childConfig, err)\n\t\t}\n\t\tif _, err := parser.ParseConfig(jsonCfg); err != nil {\n\t\t\treturn \"\", nil, fmt.Errorf(\"rls: childPolicy config validation failed: %v\", err)","sourceCodeStart":282,"sourceCodeEnd":318,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/balancer/rls/config.go#L282-L318","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Switch the childPolicy to a balancer that implements ConfigParser (round_robin, weighted_round_robin, cds, xds_cluster_resolver, etc.).","If you maintain the child balancer, implement balancer.ConfigParser (ParseConfig(json.RawMessage) (LoadBalancingConfig, error)) on its builder.","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)."],"exampleFix":"// before: 'custom_lb' builder has no ConfigParser\n\"childPolicy\": [ { \"custom_lb\": {} } ]\n\n// after: use a balancer that supports config parsing\n\"childPolicy\": [ { \"round_robin\": {} } ]\n// or implement on custom_lb:\n// func (b *customLBBuilder) ParseConfig(raw json.RawMessage) (serviceconfig.LoadBalancingConfig, error) { ... }","handlingStrategy":"type-guard","validationCode":"func childPolicySupportsParsing(name string) bool {\n    b := balancer.Get(name)\n    if b == nil {\n        return false\n    }\n    _, ok := b.(balancer.ConfigParser)\n    return ok\n}","typeGuard":"func isConfigParser(b balancer.Builder) bool {\n    _, ok := b.(balancer.ConfigParser)\n    return ok\n}","tryCatchPattern":null,"preventionTips":["Prefer core balancers (round_robin, pick_first) that implement ConfigParser.","If you maintain a child balancer, implement balancer.ConfigParser on its Builder.","Unit-test that balancer.Get(name).(balancer.ConfigParser) succeeds for each child you list."],"tags":["rls","child-policy","balancer","config-parser"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}