{"record":{"id":"ad4e38dc8d5dde2c","repo":"grpc/grpc-java","slug":"there-are-size-fields-in-a-loadbalancingconfig","errorCode":null,"errorMessage":"There are ${size} fields in a LoadBalancingConfig object. Exactly one is expected. Config=${lbConfig}","messagePattern":"There are (.+?) fields in a LoadBalancingConfig object\\. Exactly one is expected\\. Config=(.+?)","errorType":"validation","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/io/grpc/internal/ServiceConfigUtil.java","lineNumber":313,"sourceCode":"      String policy = JsonUtil.getString(serviceConfig, \"loadBalancingPolicy\");\n      if (policy != null) {\n        // Convert the policy to a config, so that the caller can handle them in the same way.\n        policy = policy.toLowerCase(Locale.ROOT);\n        Map<String, ?> fakeConfig = Collections.singletonMap(policy, Collections.emptyMap());\n        lbConfigs.add(fakeConfig);\n      }\n    }\n    return Collections.unmodifiableList(lbConfigs);\n  }\n\n  /**\n   * Unwrap a LoadBalancingConfig JSON object into a {@link LbConfig}.  The input is a JSON object\n   * (map) with exactly one entry, where the key is the policy name and the value is a config object\n   * for that policy.\n   */\n  public static LbConfig unwrapLoadBalancingConfig(Map<String, ?> lbConfig) {\n    if (lbConfig.size() != 1) {\n      throw new RuntimeException(\n          \"There are \" + lbConfig.size() + \" fields in a LoadBalancingConfig object. Exactly one\"\n          + \" is expected. Config=\" + lbConfig);\n    }\n    String key = lbConfig.entrySet().iterator().next().getKey();\n    return new LbConfig(key, JsonUtil.getObject(lbConfig, key));\n  }\n\n  /**\n   * Given a JSON list of LoadBalancingConfigs, and convert it into a list of LbConfig.\n   */\n  public static List<LbConfig> unwrapLoadBalancingConfigList(List<Map<String, ?>> list) {\n    if (list == null) {\n      return null;\n    }\n    ArrayList<LbConfig> result = new ArrayList<>();\n    for (Map<String, ?> rawChildPolicy : list) {\n      result.add(unwrapLoadBalancingConfig(rawChildPolicy));\n    }","sourceCodeStart":295,"sourceCodeEnd":331,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/core/src/main/java/io/grpc/internal/ServiceConfigUtil.java#L295-L331","documentation":"gRPC service configs express the load balancing policy selection as a JSON object with exactly one entry: the policy name as key and its config object as value (e.g. {\"round_robin\":{}}). ServiceConfigUtil.unwrapLoadBalancingConfig enforces this one-entry shape; any other number of fields makes the selected policy ambiguous, so it throws a RuntimeException.","triggerScenarios":"Passing a loadBalancingConfig object with zero entries or multiple entries (e.g. {\"round_robin\":{},\"grpclb\":{}}) into unwrapLoadBalancingConfig, typically via unwrapLoadBalancingConfigList while parsing the service config.","commonSituations":"Hand-merged service configs where two policies were combined into one object; empty config objects; misunderstanding that each list element must contain exactly one policy, with selection priority expressed by the list order.","solutions":["Ensure the object has exactly one key: the policy name mapped to its config object","Split multiple policies into a list of single-entry objects: [{\"grpclb\":{}},{\"round_robin\":{}}] (list order = preference order)","If no config is needed, still provide an empty object for the policy, e.g. {\"round_robin\":{}}"],"exampleFix":"// before\n\"loadBalancingConfig\": {\"round_robin\": {}, \"grpclb\": {}}\n// after\n\"loadBalancingConfig\": [{\"grpclb\": {}}, {\"round_robin\": {}}]","handlingStrategy":"validation","validationCode":"// Pre-validate loadBalancingConfig shape\nif (lbConfig != null) {\n  if (lbConfig.size() != 1) {\n    throw new IllegalArgumentException(\n        \"loadBalancingConfig object must have exactly one entry, got \" + lbConfig.size());\n  }\n}","typeGuard":"boolean isSingleEntryLbConfig(java.util.Map<String, ?> cfg) {\n  return cfg != null && cfg.size() == 1;\n}","tryCatchPattern":"try {\n  LbConfig cfg = ServiceConfigUtil.unwrapLoadBalancingConfig(obj);\n} catch (RuntimeException e) {\n  log.error(\"Malformed loadBalancingConfig (need exactly one policy per object): \" + e.getMessage());\n  throw new ConfigInvalidException(e);\n}","preventionTips":["Express policy preference as a LIST of single-entry objects, not one multi-entry object","Keep policy name as the sole key with an empty object if no params: {\"round_robin\":{}}","Schema-validate service configs before rollout"],"tags":["grpc","service-config","load-balancing","config-shape"],"backgroundTag":"schema-validation-failed","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}