{"record":{"id":"fbd8dd52c0ecd16d","repo":"grpc/grpc-java","slug":"timeout-must-be-strictly-positive-and-valid","errorCode":null,"errorMessage":"Timeout must be strictly positive and valid","messagePattern":"Timeout must be strictly positive and valid","errorType":"validation","errorClass":"GrpcServiceParseException","httpStatus":null,"severity":"error","filePath":"xds/src/main/java/io/grpc/xds/GrpcServiceConfigParser.java","lineNumber":120,"sourceCode":"        if (key.endsWith(Metadata.BINARY_HEADER_SUFFIX)) {\n          headerValue = HeaderValue.create(key, header.getRawValue());\n        } else {\n          headerValue = HeaderValue.create(key, header.getValue());\n        }\n      } catch (IllegalArgumentException e) {\n        throw new GrpcServiceParseException(\"Invalid initial metadata header: \" + key, e);\n      }\n      if (HeaderValueValidationUtils.isDisallowed(headerValue)) {\n        throw new GrpcServiceParseException(\"Invalid initial metadata header: \" + key);\n      }\n      initialMetadata.add(headerValue);\n    }\n    builder.initialMetadata(initialMetadata.build());\n\n    if (grpcServiceProto.hasTimeout()) {\n      com.google.protobuf.Duration timeout = grpcServiceProto.getTimeout();\n      if (!Durations.isValid(timeout) || Durations.compare(timeout, Durations.ZERO) <= 0) {\n        throw new GrpcServiceParseException(\"Timeout must be strictly positive and valid\");\n      }\n      builder.timeout(Duration.ofSeconds(timeout.getSeconds(), timeout.getNanos()));\n    }\n    return builder.build();\n  }\n\n  /**\n   * Parses the {@link io.envoyproxy.envoy.config.core.v3.GrpcService.GoogleGrpc} proto to create a\n   * {@link GrpcServiceConfig.GoogleGrpcConfig} instance.\n   *\n   * @param googleGrpcProto The proto to parse.\n   * @return A {@link GrpcServiceConfig.GoogleGrpcConfig} instance.\n   * @throws GrpcServiceParseException if the proto is invalid.\n   */\n  public static GrpcServiceConfig.GoogleGrpcConfig parseGoogleGrpcConfig(\n      GrpcService.GoogleGrpc googleGrpcProto, Bootstrapper.BootstrapInfo bootstrapInfo,\n      Bootstrapper.ServerInfo serverInfo) throws GrpcServiceParseException {\n","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/xds/src/main/java/io/grpc/xds/GrpcServiceConfigParser.java#L102-L138","documentation":"Thrown by GrpcServiceConfigParser.parse when the GrpcService proto has a timeout that is either an invalid protobuf Duration (Durations.isValid fails, e.g. nanos out of [-999999999,999999999] with wrong seconds sign conventions) or is not strictly positive (zero or negative). xDS-provided GrpcService timeouts must represent a valid, positive duration.","triggerScenarios":"The xDS management server sends GrpcService.timeout as Duration{seconds:0, nanos:0} or a negative value, or a malformed Duration that fails Durations.isValid (e.g. nanos beyond 1 second bounds with inconsistent seconds sign).","commonSituations":"Control-plane bug emitting zero timeouts; hand-crafted test resources with timeout left at default zero; protobuf Duration serialization issues in custom control planes.","solutions":["Set a strictly positive timeout (e.g. seconds >= 1) in the GrpcService proto, or omit the timeout field entirely.","Fix the control-plane resource generator to emit canonical protobuf Duration values.","If a zero timeout was intended as 'no timeout', remove the field rather than sending zero."],"exampleFix":"// before (xDS resource)\ntimeout { seconds: 0 nanos: 0 }\n// after\ntimeout { seconds: 10 nanos: 0 }  // or remove the field","handlingStrategy":"validation","validationCode":"// Validate timeout before deploying the resource\ncom.google.protobuf.Duration t = grpcServiceProto.getTimeout();\nboolean ok = !grpcServiceProto.hasTimeout()\n    || (Durations.isValid(t) && Durations.compare(t, Durations.ZERO) > 0);\nif (!ok) throw new IllegalArgumentException(\"GrpcService timeout must be strictly positive\");","typeGuard":null,"tryCatchPattern":"try {\n  config = GrpcServiceConfigParser.parse(proto, bootstrapInfo, serverInfo);\n} catch (GrpcServiceParseException e) {\n  if (e.getMessage().contains(\"Timeout\")) {\n    // treat as invalid resource, request corrected config from control plane\n  }\n}","preventionTips":["Omit the timeout field instead of sending zero when no timeout is intended","Generate Duration values via protobuf helpers (Durations.fromSeconds) to keep them canonical","Add control-plane unit tests asserting positive canonical durations"],"tags":["xds","timeout","duration","validation"],"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"}