{"record":{"id":"be0d75ff92016872","repo":"grpc/grpc-java","slug":"clusterloadassignment-has-duplicate-locality-loc","errorCode":null,"errorMessage":"ClusterLoadAssignment has duplicate locality:${locality} for priority:${priority}","messagePattern":"ClusterLoadAssignment has duplicate locality:(.+?) for priority:(.+?)","errorType":"validation","errorClass":"ResourceInvalidException","httpStatus":null,"severity":"error","filePath":"xds/src/main/java/io/grpc/xds/XdsEndpointResource.java","lineNumber":144,"sourceCode":"        continue;\n      }\n      if (structOrError.getErrorDetail() != null) {\n        throw new ResourceInvalidException(structOrError.getErrorDetail());\n      }\n\n      LocalityLbEndpoints localityLbEndpoints = structOrError.getStruct();\n      int priority = localityLbEndpoints.priority();\n      maxPriority = Math.max(maxPriority, priority);\n      // Note endpoints with health status other than HEALTHY and UNKNOWN are still\n      // handed over to watching parties. It is watching parties' responsibility to\n      // filter out unhealthy endpoints. See EnvoyProtoData.LbEndpoint#isHealthy().\n      Locality locality =  parseLocality(localityLbEndpointsProto.getLocality());\n      localityLbEndpointsMap.put(locality, localityLbEndpoints);\n      if (!priorities.containsKey(priority)) {\n        priorities.put(priority, new HashSet<>());\n      }\n      if (!priorities.get(priority).add(locality)) {\n        throw new ResourceInvalidException(\"ClusterLoadAssignment has duplicate locality:\"\n            + locality + \" for priority:\" + priority);\n      }\n    }\n    if (priorities.size() != maxPriority + 1) {\n      throw new ResourceInvalidException(\"ClusterLoadAssignment has sparse priorities\");\n    }\n\n    for (ClusterLoadAssignment.Policy.DropOverload dropOverloadProto\n        : assignment.getPolicy().getDropOverloadsList()) {\n      dropOverloads.add(parseDropOverload(dropOverloadProto));\n    }\n    return new EdsUpdate(assignment.getClusterName(), localityLbEndpointsMap, dropOverloads);\n  }\n\n  private static Locality parseLocality(io.envoyproxy.envoy.config.core.v3.Locality proto) {\n    return Locality.create(proto.getRegion(), proto.getZone(), proto.getSubZone());\n  }\n","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/xds/src/main/java/io/grpc/xds/XdsEndpointResource.java#L126-L162","documentation":"Within one priority level, each Locality in a ClusterLoadAssignment must be unique. If two LocalityLbEndpoints entries map to the same Locality (region/zone/sub_zone) at the same priority, processClusterLoadAssignment rejects the EDS resource with ResourceInvalidException.","triggerScenarios":"An EDS ClusterLoadAssignment lists two LocalityLbEndpoints with identical Locality (same region, zone, sub_zone) assigned the same priority value; detected when priorities.get(priority).add(locality) returns false.","commonSituations":"Management servers aggregating endpoint data from multiple sources and emitting duplicate locality entries; service-discovery backends returning overlapping locality labels; buggy EDS generators that split one locality across entries.","solutions":["Deduplicate LocalityLbEndpoints entries by Locality key in the control plane","Merge endpoints of duplicate localities into a single LocalityLbEndpoints entry","Ensure locality labels (region/zone/sub_zone) are unique per priority in EDS output","Add control-plane-side validation before sending EDS updates"],"exampleFix":"# before (same priority, duplicate locality)\n- locality: {region: \"us-east1\", zone: \"a\"}\n  priority: 0\n- locality: {region: \"us-east1\", zone: \"a\"}\n  priority: 0\n# after\n- locality: {region: \"us-east1\", zone: \"a\"}\n  priority: 0\n  endpoints: [all addresses]","handlingStrategy":"validation","validationCode":"Set<String> seen = new HashSet<>();\nfor (LocalityLbEndpoints lle : assignment.getEndpointsList()) {\n  String key = lle.getLocality().getRegion() + \"/\" + lle.getLocality().getZone()\n      + \"/\" + lle.getLocality().getSubZone() + \"@\" + lle.getPriority();\n  if (!seen.add(key)) throw new IllegalArgumentException(\"duplicate locality/priority: \" + key);\n}","typeGuard":null,"tryCatchPattern":"try {\n  update = XdsEndpointResource.getInstance().parse(args, resource);\n} catch (ResourceInvalidException e) {\n  logger.warn(\"EDS rejected: {}\", e.getMessage());\n}","preventionTips":["Deduplicate locality entries per priority in the control plane","Merge same-locality endpoints into one LocalityLbEndpoints","Emit unique region/zone/sub_zone labels from discovery backends"],"tags":["xds","eds","locality","priority","grpc-java"],"backgroundTag":"invalid-argument-value","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}