grpc/grpc-java · error · ResourceInvalidException

outlier_detection max_ejection_time has a negative value

Error message

outlier_detection max_ejection_time has a negative value

What it means

validateOutlierDetection throws this ResourceInvalidException when outlier_detection.max_ejection_time is a valid Duration but has negative seconds or nanos. Negative ejection-time bounds are nonsensical for outlier detection's exponential backoff, so gRPC rejects the Cluster resource outright.

Source

Thrown at xds/src/main/java/io/grpc/xds/XdsClusterResource.java:406

      }
      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())) {
        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");
    }

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Set max_ejection_time to a positive duration, e.g. {seconds: 300}.
  2. Remove the field to use the default (3x base_ejection_time in Envoy semantics).
  3. Reject negative durations at config-generation time.
  4. Ensure max_ejection_time >= base_ejection_time in your generator.

Example fix

# before
outlier_detection:
  max_ejection_time: { seconds: -300 }
# after
outlier_detection:
  max_ejection_time: { seconds: 300 }
Defensive patterns

Strategy: validation

Validate before calling

boolean nonNegativeMaxEjectionTime(com.google.protobuf.Duration d) {
  return com.google.protobuf.util.Durations.isValid(d)
      && d.getSeconds() >= 0 && d.getNanos() >= 0;
}

Type guard

boolean nonNegativeDuration(com.google.protobuf.Duration d) {
  return d != null && d.getSeconds() >= 0 && d.getNanos() >= 0
      && com.google.protobuf.util.Durations.isValid(d);
}

Try / catch

try {
  parseCluster(resource);
} catch (io.grpc.xds.ResourceInvalidException e) {
  if (e.getMessage().contains("negative")) {
    log.warn("control plane emitted negative duration: {}", e.getMessage());
  }
}

Prevention

When it happens

Trigger: outlier_detection.max_ejection_time set to a negative duration (e.g. {seconds: -300} or negative nanos) in a Cluster resource processed by parseNonAggregateCluster.

Common situations: 'Unset' sentinels like -1 leaking into generated configs; buggy duration arithmetic on the control plane; copy-pasted negative values from interval fields in hand-edited YAML.

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/d6a67a5380a578b9. Report an issue: GitHub.