{"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/03255a9237b6eb32710f6bc4f2de9a675b99fe36/balancer/rls/config.go#L282-L318","documentation":"RLS delegates actual subchannel selection to a child LB policy, and to validate the child config it needs the policy to implement balancer.ConfigParser. If the resolved builder (registered via balancer.Get(name)) does not implement ConfigParser, RLS cannot parse/validate a config for it, so it errors rather than silently accepting an unvalidated config.","triggerScenarios":"Naming a child policy that exists (is registered) but takes no parseable JSON config, or providing a config object for one. E.g. naming a custom or built-in balancer that has no ParseConfig method while also passing it a non-empty config block.","commonSituations":"Using an older/preview balancer that lacks ConfigParser; referencing a policy by a wrong/legacy name; supplying a config to a no-config policy like a bare pick_first in some builds.","solutions":["Use a child policy that supports config parsing (round_robin, pick_first, weighted_round_robin are standard).","If the named policy intentionally takes no config, pass an empty config object and confirm the build registers a ConfigParser for it; otherwise switch policies.","Upgrade gRPC-Go — ConfigParser support for standard policies has been broadened over releases."],"exampleFix":"// before\n\"childPolicy\": [{ \"custom_experimental_lb\": { \"someField\": 1 } }]\n// after\n\"childPolicy\": [{ \"round_robin\": {} }]","handlingStrategy":"validation","validationCode":"func validateChildPolicyRegistered(childPolicy []map[string]json.RawMessage) error {\n    for _, entry := range childPolicy {\n        for name := range entry {\n            b := balancer.Get(name)\n            if b == nil {\n                continue // handled by error 127\n            }\n            if _, ok := b.(balancer.ConfigParser); !ok {\n                return fmt.Errorf(\"policy %q does not implement ConfigParser\", name)\n            }\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer the standard policies (round_robin, pick_first, weighted_round_robin) as RLS children.","Blank-import any custom balancer package so its init() registers it before config parse.","Confirm ConfigParser support before standardizing on a child policy."],"tags":["rls","service-config","config-validation","go","grpc","child-policy"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}