grpc/grpc-java · error · ResourceInvalidException
ClusterLoadAssignment has duplicate locality:${locality} for
Error message
ClusterLoadAssignment has duplicate locality:${locality} for priority:${priority} What it means
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.
Source
Thrown at xds/src/main/java/io/grpc/xds/XdsEndpointResource.java:144
continue;
}
if (structOrError.getErrorDetail() != null) {
throw new ResourceInvalidException(structOrError.getErrorDetail());
}
LocalityLbEndpoints localityLbEndpoints = structOrError.getStruct();
int priority = localityLbEndpoints.priority();
maxPriority = Math.max(maxPriority, priority);
// Note endpoints with health status other than HEALTHY and UNKNOWN are still
// handed over to watching parties. It is watching parties' responsibility to
// filter out unhealthy endpoints. See EnvoyProtoData.LbEndpoint#isHealthy().
Locality locality = parseLocality(localityLbEndpointsProto.getLocality());
localityLbEndpointsMap.put(locality, localityLbEndpoints);
if (!priorities.containsKey(priority)) {
priorities.put(priority, new HashSet<>());
}
if (!priorities.get(priority).add(locality)) {
throw new ResourceInvalidException("ClusterLoadAssignment has duplicate locality:"
+ locality + " for priority:" + priority);
}
}
if (priorities.size() != maxPriority + 1) {
throw new ResourceInvalidException("ClusterLoadAssignment has sparse priorities");
}
for (ClusterLoadAssignment.Policy.DropOverload dropOverloadProto
: assignment.getPolicy().getDropOverloadsList()) {
dropOverloads.add(parseDropOverload(dropOverloadProto));
}
return new EdsUpdate(assignment.getClusterName(), localityLbEndpointsMap, dropOverloads);
}
private static Locality parseLocality(io.envoyproxy.envoy.config.core.v3.Locality proto) {
return Locality.create(proto.getRegion(), proto.getZone(), proto.getSubZone());
}
View on GitHub (pinned to 64daddc1f3)
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
Example fix
# before (same priority, duplicate locality)
- locality: {region: "us-east1", zone: "a"}
priority: 0
- locality: {region: "us-east1", zone: "a"}
priority: 0
# after
- locality: {region: "us-east1", zone: "a"}
priority: 0
endpoints: [all addresses] Defensive patterns
Strategy: validation
Validate before calling
Set<String> seen = new HashSet<>();
for (LocalityLbEndpoints lle : assignment.getEndpointsList()) {
String key = lle.getLocality().getRegion() + "/" + lle.getLocality().getZone()
+ "/" + lle.getLocality().getSubZone() + "@" + lle.getPriority();
if (!seen.add(key)) throw new IllegalArgumentException("duplicate locality/priority: " + key);
} Try / catch
try {
update = XdsEndpointResource.getInstance().parse(args, resource);
} catch (ResourceInvalidException e) {
logger.warn("EDS rejected: {}", e.getMessage());
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- ClusterLoadAssignment has sparse priorities
- Invalid message type: ${unpackedMessage.getClass()}
- ${structOrError.getErrorDetail()}
- Unknown denominator type of ${percent}
- LocalCredentials are not supported in grpc-java. See https:/
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/be0d75ff92016872.
Report an issue: GitHub.