{"record":{"id":"52acfcbc4d4f0a3d","repo":"grpc/grpc-go","slug":"invalid-loadbalancingconfig-entry-v-does-not-con","errorCode":null,"errorMessage":"invalid loadBalancingConfig: entry %v does not contain exactly 1 policy/config pair: %q","messagePattern":"invalid loadBalancingConfig: entry (.+?) does not contain exactly 1 policy/config pair: %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/serviceconfig/serviceconfig.go","lineNumber":84,"sourceCode":"//\n// ServiceConfig contains a list of loadBalancingConfigs, each with a name and\n// config. This method iterates through that list in order, and stops at the\n// first policy that is supported.\n//   - If the config for the first supported policy is invalid, the whole service\n//     config is invalid.\n//   - If the list doesn't contain any supported policy, the whole service config\n//     is invalid.\nfunc (bc *BalancerConfig) UnmarshalJSON(b []byte) error {\n\tvar ir intermediateBalancerConfig\n\terr := json.Unmarshal(b, &ir)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar names []string\n\tfor i, lbcfg := range ir {\n\t\tif len(lbcfg) != 1 {\n\t\t\treturn fmt.Errorf(\"invalid loadBalancingConfig: entry %v does not contain exactly 1 policy/config pair: %q\", i, lbcfg)\n\t\t}\n\n\t\tvar (\n\t\t\tname    string\n\t\t\tjsonCfg json.RawMessage\n\t\t)\n\t\t// Get the key:value pair from the map. We have already made sure that\n\t\t// the map contains a single entry.\n\t\tfor name, jsonCfg = range lbcfg {\n\t\t}\n\n\t\tnames = append(names, name)\n\t\tbuilder := balancer.Get(name)\n\t\tif builder == nil {\n\t\t\t// If the balancer is not registered, move on to the next config.\n\t\t\t// This is not an error.\n\t\t\tcontinue\n\t\t}","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/serviceconfig/serviceconfig.go#L66-L102","documentation":"This error occurs in BalancerConfig.UnmarshalJSON when a loadBalancingConfig array entry is a JSON object that does not contain exactly one key (policy name -> config). gRPC's service config spec requires each entry to be a single-key map like [{\"round_robin\": {}}]. Entries with zero keys ({}) or multiple keys ({\"a\":{}, \"b\":{}}) are rejected.","triggerScenarios":"Parsing a service config whose loadBalancingConfig array contains an entry with 0 or 2+ keys. For example: \"loadBalancingConfig\": [{\"round_robin\": {}, \"grpclb\": {}}] or \"loadBalancingConfig\": [{}].","commonSituations":"Malformed service config from a custom name resolver or xDS control plane, hand-crafted JSON that groups multiple policies into one object instead of separate array entries, or tooling that serializes balancer config incorrectly.","solutions":["Ensure each loadBalancingConfig array element is a single-key JSON object: [{\"policy_name\": {config}}].","Split multi-policy entries into separate array elements: [{\"a\": {}}, {\"b\": {}}] not [{\"a\": {}, \"b\": {}}].","Validate the service config JSON structure against the gRPC service_config.proto before passing it to the client."],"exampleFix":"// before (broken): two policies in one entry\n\"loadBalancingConfig\": [{\"round_robin\": {}, \"pick_first\": {}}]\n\n// after (valid): one policy per entry, ordered by preference\n\"loadBalancingConfig\": [{\"round_robin\": {}}, {\"pick_first\": {}}]","handlingStrategy":"validation","validationCode":"// Validate that each loadBalancingConfig entry is a single-key map\nfunc validateLoadBalancingConfig(raw []byte) error {\n    var entries []map[string]json.RawMessage\n    if err := json.Unmarshal(raw, &entries); err != nil { return err }\n    for i, e := range entries {\n        if len(e) != 1 {\n            return fmt.Errorf(\"entry %d must have exactly 1 policy, got %d\", i, len(e))\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"var bc serviceconfig.BalancerConfig\nif err := json.Unmarshal(raw, &bc); err != nil {\n    if strings.Contains(err.Error(), \"does not contain exactly 1\") {\n        // fix the config source or use default balancer\n    }\n    return err\n}","preventionTips":["Generate service config using gRPC's own BalancerConfig.MarshalJSON to ensure correct structure.","Validate the JSON schema of service configs from control planes before applying.","Document the single-key-per-entry rule for teams writing service configs."],"tags":["service-config","load-balancing","json-parsing","balancer","configuration"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}