grpc/grpc-java · error · ResourceInvalidException
outlier_detection max_ejection_percent is > 100
Error message
outlier_detection max_ejection_percent is > 100
What it means
This ResourceInvalidException is thrown when outlier_detection.max_ejection_percent exceeds 100. The field caps the percentage of hosts in a cluster that can be ejected for outlier status, so any value above 100 is invalid. validateOutlierDetection enforces this range while parsing the Cluster in parseNonAggregateCluster.
Solutions
- Set max_ejection_percent to a value in [0, 100] (Envoy default is 10).
- Multiply fraction-based values by 100 (0.5 -> 50) before emitting.
- Add range validation in the control plane before publishing the Cluster.
- If you truly need all hosts ejectable, set it to exactly 100, not more.
Example fix
# before outlier_detection: max_ejection_percent: 150 # after outlier_detection: max_ejection_percent: 100
Defensive patterns
Strategy: validation
Validate before calling
boolean validMaxEjectionPercent(io.envoyproxy.envoy.type.v3.UInt32Value v) {
return v == null || v.getValue() <= 100;
} Type guard
boolean inPercentRange(long v) {
return v >= 0 && v <= 100;
} Try / catch
try {
cluster = parseCluster(raw);
} catch (io.grpc.xds.ResourceInvalidException e) {
if (e.getMessage().contains("max_ejection_percent")) {
log.error("max_ejection_percent > 100 in CDS resource; fix control plane");
}
return null;
} Prevention
- Clamp percent fields to 0..100 at config generation.
- Distinguish percent (0-100) from fraction (0-1) and per-ten-thousand scales in your schema.
- Validate user input from dashboards before mapping into Cluster protos.
- Use named constants (MAX_EJECTION_PERCENT_DEFAULT = 10) instead of raw numbers.
When it happens
Trigger: A Cluster resource contains outlier_detection.max_ejection_percent with a UInt32Value greater than 100 (e.g. 150). The check runs only when the field is present (hasMaxEjectionPercent()).
Common situations: Confusing the 0-100 percent scale with a 0-1 fraction and sending 1.0 as 1000; typos like 1000; control planes forwarding unvalidated user input from dashboards.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- outlier_detection enforcing_success_rate is > 100
- outlier_detection failure_percentage_threshold is > 100
- A terminal HttpFilter must be the last filter
- AndMatcher must have at least 2 predicates
- client_listener_resource_name_template
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/238def3a464c02b6.
Report an issue: GitHub.
Appendix: source
Thrown at xds/src/main/java/io/grpc/xds/XdsClusterResource.java:411
}
if (outlierDetection.hasMaxEjectionTime()) {
if (!Durations.isValid(outlierDetection.getMaxEjectionTime())) {
throw new ResourceInvalidException(
"outlier_detection max_ejection_time is not a valid Duration");
}
if (hasNegativeValues(outlierDetection.getMaxEjectionTime())) {
throw new ResourceInvalidException(
"outlier_detection max_ejection_time has a negative value");
}
}
if (outlierDetection.hasMaxEjectionPercent()
&& outlierDetection.getMaxEjectionPercent().getValue() > 100) {
throw new ResourceInvalidException(
"outlier_detection max_ejection_percent is > 100");
}
if (outlierDetection.hasEnforcingSuccessRate()
&& outlierDetection.getEnforcingSuccessRate().getValue() > 100) {
throw new ResourceInvalidException(
"outlier_detection enforcing_success_rate is > 100");
}
if (outlierDetection.hasFailurePercentageThreshold()
&& outlierDetection.getFailurePercentageThreshold().getValue() > 100) {
throw new ResourceInvalidException(
"outlier_detection failure_percentage_threshold is > 100");
}
if (outlierDetection.hasEnforcingFailurePercentage()
&& outlierDetection.getEnforcingFailurePercentage().getValue() > 100) {
throw new ResourceInvalidException(
"outlier_detection enforcing_failure_percentage is > 100");
}
return outlierDetection;
}
static boolean hasNegativeValues(Duration duration) {
return duration.getSeconds() < 0 || duration.getNanos() < 0;View on GitHub (pinned to 64daddc1f3)