{"record":{"id":"a6d296a62f01eab8","repo":"grpc/grpc-java","slug":"outlier-detection-base-ejection-time-has-a-negativ","errorCode":null,"errorMessage":"outlier_detection base_ejection_time has a negative value","messagePattern":"outlier_detection base_ejection_time has a negative value","errorType":"validation","errorClass":"ResourceInvalidException","httpStatus":null,"severity":"error","filePath":"xds/src/main/java/io/grpc/xds/XdsClusterResource.java","lineNumber":390,"sourceCode":"\n  static io.envoyproxy.envoy.config.cluster.v3.OutlierDetection validateOutlierDetection(\n      io.envoyproxy.envoy.config.cluster.v3.OutlierDetection outlierDetection)\n      throws ResourceInvalidException {\n    if (outlierDetection.hasInterval()) {\n      if (!Durations.isValid(outlierDetection.getInterval())) {\n        throw new ResourceInvalidException(\"outlier_detection interval is not a valid Duration\");\n      }\n      if (hasNegativeValues(outlierDetection.getInterval())) {\n        throw new ResourceInvalidException(\"outlier_detection interval has a negative value\");\n      }\n    }\n    if (outlierDetection.hasBaseEjectionTime()) {\n      if (!Durations.isValid(outlierDetection.getBaseEjectionTime())) {\n        throw new ResourceInvalidException(\n            \"outlier_detection base_ejection_time is not a valid Duration\");\n      }\n      if (hasNegativeValues(outlierDetection.getBaseEjectionTime())) {\n        throw new ResourceInvalidException(\n            \"outlier_detection base_ejection_time has a negative value\");\n      }\n    }\n    if (outlierDetection.hasMaxEjectionTime()) {\n      if (!Durations.isValid(outlierDetection.getMaxEjectionTime())) {\n        throw new ResourceInvalidException(\n            \"outlier_detection max_ejection_time is not a valid Duration\");\n      }\n      if (hasNegativeValues(outlierDetection.getMaxEjectionTime())) {\n        throw new ResourceInvalidException(\n            \"outlier_detection max_ejection_time has a negative value\");\n      }\n    }\n    if (outlierDetection.hasMaxEjectionPercent()\n        && outlierDetection.getMaxEjectionPercent().getValue() > 100) {\n      throw new ResourceInvalidException(\n          \"outlier_detection max_ejection_percent is > 100\");\n    }","sourceCodeStart":372,"sourceCodeEnd":408,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/xds/src/main/java/io/grpc/xds/XdsClusterResource.java#L372-L408","documentation":"This ResourceInvalidException is raised when outlier_detection.base_ejection_time is a structurally valid Duration but contains negative seconds or nanos. validateOutlierDetection enforces that all outlier-detection durations are non-negative because a negative ejection time has no semantics. The Cluster resource is rejected and will not be applied.","triggerScenarios":"outlier_detection.base_ejection_time set to a negative duration, e.g. {seconds: -30} or {seconds: 0, nanos: -1}, in a Cluster resource parsed by parseNonAggregateCluster.","commonSituations":"Control-plane templates inserting -1 as 'not set'; manual YAML edits; generators that subtract timestamps to compute durations and go negative on clock skew.","solutions":["Set base_ejection_time to a positive duration (Envoy default is 30s, e.g. {seconds: 30}).","Omit the field to use the library default.","Add a pre-publish validation on the control plane rejecting negative durations.","Audit any code computing durations by subtraction for clock-skew bugs."],"exampleFix":"# before\noutlier_detection:\n  base_ejection_time: { seconds: -30 }\n# after\noutlier_detection:\n  base_ejection_time: { seconds: 30 }","handlingStrategy":"validation","validationCode":"boolean nonNegativeBaseEjectionTime(com.google.protobuf.Duration d) {\n  return com.google.protobuf.util.Durations.isValid(d)\n      && d.getSeconds() >= 0 && d.getNanos() >= 0;\n}","typeGuard":"boolean nonNegative(com.google.protobuf.Duration d) {\n  return d != null\n      && com.google.protobuf.util.Durations.compare(d,\n          com.google.protobuf.Duration.getDefaultInstance()) >= 0;\n}","tryCatchPattern":"try {\n  cluster = parseCluster(raw);\n} catch (io.grpc.xds.ResourceInvalidException e) {\n  log.warn(\"invalid outlier_detection config: {}\", e.getMessage());\n  return ClusterUpdate.unknownError();\n}","preventionTips":["Reject negative durations at config authoring time, not at xDS client parse time.","Replace -1/'unset' sentinels with field absence.","Check any duration computed by timestamp subtraction for clock skew.","Add unit tests covering negative-value rejection in your config generator."],"tags":["xds","grpc","config-validation","duration"],"backgroundTag":"invalid-duration-format","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}