{"record":{"id":"8b3db3de42a7c8ed","repo":"grpc/grpc-go","slug":"rls-childpolicyconfigtargetfieldname-field-is-not","errorCode":null,"errorMessage":"rls: childPolicyConfigTargetFieldName field is not set in service config %+v","messagePattern":"rls: childPolicyConfigTargetFieldName field is not set in service config %\\+v","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"balancer/rls/config.go","lineNumber":174,"sourceCode":"\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) {\n\t// Validations specified on the `grpc_keybuilders` field are performed here.\n\tkbMap, err := keys.MakeBuilderMap(rlsProto)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/balancer/rls/config.go#L156-L192","documentation":"Returned by rls.ParseConfig (config.go:173-175) when ChildPolicyConfigTargetFieldName is empty. RLS swaps the target field of its child policy config with each looked-up target, so it must know which field name to overwrite (e.g. \"target\" for pick_first, \"endpoint\" in xDS). An empty value makes target substitution impossible, so it is required.","triggerScenarios":"The RLS service config omits childPolicyConfigTargetFieldName, or sets it to \"\".","commonSituations":"Hand-writing RLS config and forgetting the field. Control plane not populating it because the child policy type is ambiguous.","solutions":["Set childPolicyConfigTargetFieldName to the target field name expected by the chosen child policy (commonly \"target\" for pick_first/round_robin-style policies).","Ensure the value matches the field name your child policy uses to receive its address/target."],"exampleFix":"// before\ncfg.ChildPolicyConfigTargetFieldName = \"\"\n\n// after\ncfg.ChildPolicyConfigTargetFieldName = \"target\"","handlingStrategy":"validation","validationCode":"func validateTargetFieldName(cfg map[string]any) error {\n    v, _ := cfg[\"childPolicyConfigTargetFieldName\"].(string)\n    if v == \"\" {\n        return errors.New(\"childPolicyConfigTargetFieldName must be set\")\n    }\n    return nil\n}","typeGuard":"func hasTargetFieldName(cfg map[string]any) bool {\n    v, _ := cfg[\"childPolicyConfigTargetFieldName\"].(string)\n    return v != \"\"\n}","tryCatchPattern":null,"preventionTips":["Always set childPolicyConfigTargetFieldName (typically \"target\").","Use a typed config builder that requires the field."],"tags":["go","grpc","load-balancing","rls","config"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}