{"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/0c51461d27177d997e14c642fe18c11668fc09a3/internal/serviceconfig/serviceconfig.go#L66-L102","documentation":"Fires in BalancerConfig.UnmarshalJSON (serviceconfig.go:84) when an element of the loadBalancingConfig JSON array is not a single-key map mapping one policy name to its config object. gRPC's service-config schema requires each loadBalancingConfig entry to contain exactly one policy-name -> config pair, so the parser can walk them in order and pick the first supported one.","triggerScenarios":"A loadBalancingConfig array entry whose JSON object has zero keys (e.g. [{}]) or two-or-more keys (e.g. [{\"round_robin\": {}, \"grpclb\": {}}]). The check len(lbcfg) != 1 catches both. Also triggered by malformed JSON object syntax that json.Unmarshal still parses into a multi-key map.","commonSituations":"Hand-editing service config and accidentally merging two policies into one object; a config builder that emits all policies into a single map instead of separate array entries; misunderstanding the schema (the array-of-single-key-maps shape is non-obvious).","solutions":["Reformat the offending entry so each array element is an object with exactly one key: [{\"policyA\": {}}, {\"policyB\": {}}].","Use the library's BalancerConfig.MarshalJSON to generate valid output from a Go struct instead of hand-writing JSON.","Validate the service config against the official gRPC service_config.proto JSON schema before applying."],"exampleFix":"// before\n// \"loadBalancingConfig\": [\n//   { \"round_robin\": {}, \"pick_first\": {} }   // two keys in one entry\n// ]\n\n// after\n// \"loadBalancingConfig\": [\n//   { \"round_robin\": {} },\n//   { \"pick_first\": {} }\n// ]","handlingStrategy":"validation","validationCode":"// Validate that each loadBalancingConfig entry is a single-key map.\nfunc validateLBConfig(raw []byte) error {\n    var entries []map[string]json.RawMessage\n    if err := json.Unmarshal(raw, &entries); err != nil {\n        return err\n    }\n    for i, e := range entries {\n        if len(e) != 1 {\n            return fmt.Errorf(\"entry %d has %d keys; want exactly 1\", i, len(e))\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"var bc svcconfig.BalancerConfig\nif err := json.Unmarshal(lbJSON, &bc); err != nil {\n    // err contains \"does not contain exactly 1 policy/config pair\"\n    return err\n}","preventionTips":["Emit loadBalancingConfig via BalancerConfig.MarshalJSON from Go structs.","Validate against the service_config.proto JSON schema before applying.","Remember each array element must be an object with exactly one policy-name key."],"tags":["config","loadbalancing","service-config","json"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}