grpc/grpc-java · error · ResourceInvalidException
outlier_detection interval has a negative value
Error message
outlier_detection interval has a negative value
What it means
This ResourceInvalidException is thrown by XdsClusterResource.validateOutlierDetection when an xDS Cluster's outlier_detection.interval field is set to a Duration containing negative components (seconds or nanos). The library validates every xDS cluster resource received from the control plane and rejects configs it cannot faithfully implement. A negative interval would make the passive health-checking schedule meaningless, so the resource is rejected instead of being silently normalized.
Source
Thrown at xds/src/main/java/io/grpc/xds/XdsClusterResource.java:381
String dnsHostName = String.format(
Locale.US, "%s:%d", socketAddress.getAddress(), socketAddress.getPortValue());
return StructOrError.fromStruct(CdsUpdate.forLogicalDns(
clusterName, dnsHostName, lrsServerInfo, maxConcurrentRequests,
upstreamTlsContext, isHttp11ProxyAvailable, backendMetricPropagation));
}
return StructOrError.fromError(
"Cluster " + clusterName + ": unsupported built-in discovery type: " + type);
}
static io.envoyproxy.envoy.config.cluster.v3.OutlierDetection validateOutlierDetection(
io.envoyproxy.envoy.config.cluster.v3.OutlierDetection outlierDetection)
throws ResourceInvalidException {
if (outlierDetection.hasInterval()) {
if (!Durations.isValid(outlierDetection.getInterval())) {
throw new ResourceInvalidException("outlier_detection interval is not a valid Duration");
}
if (hasNegativeValues(outlierDetection.getInterval())) {
throw new ResourceInvalidException("outlier_detection interval has a negative value");
}
}
if (outlierDetection.hasBaseEjectionTime()) {
if (!Durations.isValid(outlierDetection.getBaseEjectionTime())) {
throw new ResourceInvalidException(
"outlier_detection base_ejection_time is not a valid Duration");
}
if (hasNegativeValues(outlierDetection.getBaseEjectionTime())) {
throw new ResourceInvalidException(
"outlier_detection base_ejection_time has a negative value");
}
}
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())) {View on GitHub (pinned to 64daddc1f3)
Solutions
- Fix the control plane or config so outlier_detection.interval is a positive duration (e.g. {seconds: 10}).
- If the field should be unset, remove the interval field entirely rather than sending a zero/negative value.
- Verify with the envoy protos that Duration values use non-negative seconds and nanos (nanos in [0, 999999999]).
- Upgrade the xDS management server if it is emitting negative defaults.
Example fix
# before (CDS response)
outlier_detection:
interval: { seconds: -5 }
# after
outlier_detection:
interval: { seconds: 10 } Defensive patterns
Strategy: validation
Validate before calling
import static com.google.protobuf.util.Durations.*;
boolean isValidInterval(com.google.protobuf.Duration d) {
return isValid(d) && d.getSeconds() >= 0 && d.getNanos() >= 0;
}
// apply to cluster.getOutlierDetection().getInterval() when hasInterval() Type guard
boolean nonNegativeDuration(com.google.protobuf.Duration d) {
return d != null && com.google.protobuf.util.Durations.isValid(d)
&& d.getSeconds() >= 0 && d.getNanos() >= 0;
} Try / catch
try {
cluster = XdsClusterResource.parseCluster(rawCluster, ...);
} catch (io.grpc.xds.ResourceInvalidException e) {
log.warn("rejecting invalid CDS resource: " + e.getMessage());
return null; // skip resource, keep previous config
} Prevention
- Validate Duration fields (seconds >= 0, nanos in [0, 999999999]) in the control plane before publishing.
- Never use -1 as a sentinel for unset durations; omit the field instead.
- Test generated Cluster resources against protobuf Duration validity rules.
- Pin and test the management server version that serializes CDS.
When it happens
Trigger: An xDS management server (or hand-written proto/JSON Cluster config) sends a Cluster whose outlier_detection.interval is a Duration with a negative seconds or nanoseconds value, e.g. interval: {seconds: -5} or {seconds: 0, nanos: -100}. The value must pass Durations.isValid() first, so this fires only for structurally valid but negative durations during parseNonAggregateCluster.
Common situations: Control-plane bugs emitting default/negative durations; hand-edited bootstrap or LDS/CDS YAML where a '-' was left in the value; templated config generators producing -1 as a sentinel for 'unset'; proto JSON where nanos is negative to represent a truncation artifact.
Understand the failure class
Background: "invalid duration" / "failed to parse duration": why your timeout, interval, or TTL string is rejected and which formats each library accepts — this error's family across 32 libraries.
Related errors
- outlier_detection base_ejection_time is not a valid Duration
- outlier_detection base_ejection_time has a negative value
- outlier_detection max_ejection_time is not a valid Duration
- outlier_detection max_ejection_time has a negative value
- unsupported ExtAuthz service type: only grpc_service is supp
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/5c74d4c633044247.
Report an issue: GitHub.