{"record":{"id":"b72f7ffa3506e067","repo":"grpc/grpc-go","slug":"rls-bad-control-channel-service-config-q-v","errorCode":null,"errorMessage":"rls: bad control channel service config %q: %v","messagePattern":"rls: bad control channel service config %q: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"balancer/rls/config.go","lineNumber":168,"sourceCode":"\tcfgJSON := &lbConfigJSON{}\n\tif err := json.Unmarshal(c, cfgJSON); err != nil {\n\t\treturn nil, fmt.Errorf(\"rls: json unmarshal failed for service config %+v: %v\", string(c), err)\n\t}\n\n\tm := protojson.UnmarshalOptions{DiscardUnknown: true}\n\trlsProto := &rlspb.RouteLookupConfig{}\n\tif err := m.Unmarshal(cfgJSON.RouteLookupConfig, rlsProto); err != nil {\n\t\treturn nil, fmt.Errorf(\"rls: bad RouteLookupConfig proto %+v: %v\", string(cfgJSON.RouteLookupConfig), err)\n\t}\n\tlbCfg, err := parseRLSProto(rlsProto)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif sc := string(cfgJSON.RouteLookupChannelServiceConfig); sc != \"\" {\n\t\tparsed := internal.ParseServiceConfig.(func(string) *serviceconfig.ParseResult)(sc)\n\t\tif parsed.Err != nil {\n\t\t\treturn nil, fmt.Errorf(\"rls: bad control channel service config %q: %v\", sc, parsed.Err)\n\t\t}\n\t\tlbCfg.controlChannelServiceConfig = sc\n\t}\n\n\tif cfgJSON.ChildPolicyConfigTargetFieldName == \"\" {\n\t\treturn nil, fmt.Errorf(\"rls: childPolicyConfigTargetFieldName field is not set in service config %+v\", string(c))\n\t}\n\tname, config, err := parseChildPolicyConfigs(cfgJSON.ChildPolicy, cfgJSON.ChildPolicyConfigTargetFieldName)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tlbCfg.childPolicyName = name\n\tlbCfg.childPolicyConfig = config\n\tlbCfg.childPolicyTargetField = cfgJSON.ChildPolicyConfigTargetFieldName\n\treturn lbCfg, nil\n}\n\nfunc parseRLSProto(rlsProto *rlspb.RouteLookupConfig) (*lbConfig, error) {","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/balancer/rls/config.go#L150-L186","documentation":"Returned by rls.ParseConfig (config.go:165-169) when routeLookupChannelServiceConfig is non-empty and internal.ParseServiceConfig reports an error. The control channel is the separate channel RLS uses to talk to the RLS server, and its service config (if provided) must itself be a valid gRPC service config. The %q is the offending service-config string and %v the parse error.","triggerScenarios":"The optional routeLookupChannelServiceConfig field is set but is not valid gRPC service-config JSON (e.g. unknown methodConfig, bad loadBalancingConfig, syntax error).","commonSituations":"Copy-pasting a loadBalancingConfig into routeLookupChannelServiceConfig. Providing a config meant for the data channel, not the control channel. Control-plane emitting an outdated service-config schema.","solutions":["Read the %v parse error and fix the offending field in the control-channel service config.","If you do not need a custom control-channel service config, omit routeLookupChannelServiceConfig entirely.","Validate the string with grpc's own service-config parser semantics (retry/methodConfig/loadBalancingConfig) before shipping."],"exampleFix":"// before: invalid service config for the control channel\ncfg.RouteLookupChannelServiceConfig = `{ \"loadBalancingConfig\": [ { \"not_a_policy\": {} } ] }`\n\n// after: valid policy (or omit the field)\ncfg.RouteLookupChannelServiceConfig = `{ \"loadBalancingConfig\": [ { \"round_robin\": {} } ] }`","handlingStrategy":"validation","validationCode":"// Reuse grpc's parser: this mirrors what ParseConfig does internally.\nimport \"google.golang.org/grpc/internal\"\n\nfunc validateControlChannelSC(sc string) error {\n    if sc == \"\" { return nil }\n    pr := internal.ParseServiceConfig.(func(string) *serviceconfig.ParseResult)(sc)\n    return pr.Err\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Omit routeLookupChannelServiceConfig unless you need to tune the control channel.","When set, use a minimal valid service config (e.g. just a loadBalancingConfig)."],"tags":["go","grpc","load-balancing","rls","config","service-config"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}