{"record":{"id":"d3ee405a890bb669","repo":"grpc/grpc-java","slug":"outlier-detection-interval-is-not-a-valid-duration","errorCode":null,"errorMessage":"outlier_detection interval is not a valid Duration","messagePattern":"outlier_detection interval is not a valid Duration","errorType":"validation","errorClass":"ResourceInvalidException","httpStatus":null,"severity":"error","filePath":"xds/src/main/java/io/grpc/xds/XdsClusterResource.java","lineNumber":378,"sourceCode":"            \"Cluster \" + clusterName\n                + \": LOGICAL DNS clusters socket_address must have port_value\");\n      }\n      String dnsHostName = String.format(\n          Locale.US, \"%s:%d\", socketAddress.getAddress(), socketAddress.getPortValue());\n      return StructOrError.fromStruct(CdsUpdate.forLogicalDns(\n          clusterName, dnsHostName, lrsServerInfo, maxConcurrentRequests,\n          upstreamTlsContext, isHttp11ProxyAvailable, backendMetricPropagation));\n    }\n    return StructOrError.fromError(\n        \"Cluster \" + clusterName + \": unsupported built-in discovery type: \" + type);\n  }\n\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(","sourceCodeStart":360,"sourceCodeEnd":396,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/xds/src/main/java/io/grpc/xds/XdsClusterResource.java#L360-L396","documentation":"validateOutlierDetection checks the outlier_detection settings of a Cluster. If the interval duration proto is present but not a valid Duration (e.g. out-of-range seconds/nanos per Duration validation rules), the whole CDS resource is rejected with ResourceInvalidException.","triggerScenarios":"A Cluster's outlier_detection.interval is set with values outside Duration limits — negative seconds with wrong nanos normalization, or seconds/nanos exceeding protobuf Duration bounds — such that Durations.isValid returns false.","commonSituations":"Control-plane bugs producing unnormalized Duration protos; hand-built cluster protos in tests with seconds > 315,576,000,000 or malformed nanos; config converters translating durations incorrectly.","solutions":["Set a valid, normalized non-negative Duration for outlier_detection.interval on the management server","Ensure seconds and nanos fields are within protobuf Duration bounds and correctly normalized","Validate durations server-side before emitting CDS resources"],"exampleFix":"// before\nDurations.newBuilder().setSeconds(999999999999L).setNanos(0).build() // interval\n// after\ncom.google.protobuf.Duration.newBuilder().setSeconds(10).setNanos(0).build() // interval = 10s","handlingStrategy":"validation","validationCode":"io.envoyproxy.envoy.config.cluster.v3.OutlierDetection od = cluster.getOutlierDetection();\nif (od.hasInterval() && !Durations.isValid(od.getInterval())) {\n  throw new IllegalArgumentException(\"interval is not a valid Duration\");\n}\nif (od.hasInterval() && od.getInterval().getSeconds() < 0) {\n  throw new IllegalArgumentException(\"interval is negative\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  cdsUpdate = xdsClusterResource.parseResource(args);\n} catch (ResourceInvalidException e) {\n  if (e.getMessage().contains(\"not a valid Duration\")) {\n    logger.atWarning().log(\"Rejecting cluster outlier_detection: %s\", e.getMessage());\n  }\n}","preventionTips":["Build Durations via Durations.fromMillis/fromSeconds to guarantee validity","Never hand-set seconds/nanos without normalization","Validate durations server-side before emitting outlier_detection settings"],"tags":["grpc","xds","outlier-detection","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-17T15:17:12.973Z"}