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

  1. Fix the control plane or config so outlier_detection.interval is a positive duration (e.g. {seconds: 10}).
  2. If the field should be unset, remove the interval field entirely rather than sending a zero/negative value.
  3. Verify with the envoy protos that Duration values use non-negative seconds and nanos (nanos in [0, 999999999]).
  4. 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

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


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/5c74d4c633044247. Report an issue: GitHub.