{"record":{"id":"9156e3c6d71ff566","repo":"grpc/grpc-java","slug":"outlier-detection-base-ejection-time-is-not-a-vali","errorCode":null,"errorMessage":"outlier_detection base_ejection_time is not a valid Duration","messagePattern":"outlier_detection base_ejection_time is not a valid Duration","errorType":"validation","errorClass":"ResourceInvalidException","httpStatus":null,"severity":"error","filePath":"xds/src/main/java/io/grpc/xds/XdsClusterResource.java","lineNumber":386,"sourceCode":"    }\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(\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()","sourceCodeStart":368,"sourceCodeEnd":404,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/xds/src/main/java/io/grpc/xds/XdsClusterResource.java#L368-L404","documentation":"validateOutlierDetection throws this ResourceInvalidException when the outlier_detection.base_ejection_time field is present but is not a valid protobuf Duration (Durations.isValid fails, e.g. nanos out of range). The gRPC xDS client rejects the whole Cluster resource because it cannot interpret the ejection duration. The config must be corrected at the management server before the cluster can load.","triggerScenarios":"A Cluster resource from the xDS server carries outlier_detection.base_ejection_time with an invalid Duration value — nanos outside [0, 999999999] or seconds outside the representable range — detected in parseNonAggregateCluster via validateOutlierDetection.","commonSituations":"Malformed proto-JSON like {nanos: 1000000000} instead of {seconds: 1}; control-plane serialization bugs; hand-crafted test fixtures with placeholder durations; mixing -inf/NaN-like sentinels into duration fields.","solutions":["Correct base_ejection_time to a valid Duration, e.g. {seconds: 30}.","Remove the field if you want the default base ejection time.","Validate the CDS response with a protobuf Duration validator before pushing it.","Fix the emitting control plane's duration serialization (normalize nanos into seconds)."],"exampleFix":"# before\noutlier_detection:\n  base_ejection_time: { nanos: 30000000000 }\n# after\noutlier_detection:\n  base_ejection_time: { seconds: 30 }","handlingStrategy":"validation","validationCode":"boolean validBaseEjectionTime(com.google.protobuf.Duration d) {\n  return com.google.protobuf.util.Durations.isValid(d)\n      && d.getNanos() >= 0 && d.getNanos() < 1000000000;\n}","typeGuard":"boolean isValidProtoDuration(com.google.protobuf.Duration d) {\n  return d != null && com.google.protobuf.util.Durations.isValid(d);\n}","tryCatchPattern":"try {\n  parseCluster(resource);\n} catch (io.grpc.xds.ResourceInvalidException e) {\n  if (e.getMessage().contains(\"base_ejection_time\")) {\n    log.error(\"CDS resource rejected: fix base_ejection_time on the management server\");\n  }\n}","preventionTips":["Normalize durations so nanos stay within [0, 999999999] before serialization.","Round-trip test configs through Durations.isValid before publishing.","Use well-known helper functions (Durations.fromSeconds) instead of hand-built Durations.","Avoid writing duration JSON by hand; generate it from typed values."],"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"}