{"record":{"id":"6418fb9b6f5ad1cc","repo":"grpc/grpc-java","slug":"invalid-timeout-unit-s","errorCode":null,"errorMessage":"Invalid timeout unit: %s","messagePattern":"Invalid timeout unit: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/io/grpc/internal/GrpcUtil.java","lineNumber":702,"sourceCode":"      checkArgument(serialized.length() > 0, \"empty timeout\");\n      checkArgument(serialized.length() <= 9, \"bad timeout format\");\n      long value = Long.parseLong(serialized.substring(0, serialized.length() - 1));\n      char unit = serialized.charAt(serialized.length() - 1);\n      switch (unit) {\n        case 'n':\n          return value;\n        case 'u':\n          return TimeUnit.MICROSECONDS.toNanos(value);\n        case 'm':\n          return TimeUnit.MILLISECONDS.toNanos(value);\n        case 'S':\n          return TimeUnit.SECONDS.toNanos(value);\n        case 'M':\n          return TimeUnit.MINUTES.toNanos(value);\n        case 'H':\n          return TimeUnit.HOURS.toNanos(value);\n        default:\n          throw new IllegalArgumentException(String.format(\"Invalid timeout unit: %s\", unit));\n      }\n    }\n  }\n\n  /**\n   * Returns a transport out of a PickResult, or {@code null} if the result is \"buffer\".\n   */\n  @Nullable\n  static ClientTransport getTransportFromPickResult(PickResult result, boolean isWaitForReady) {\n    final ClientTransport transport;\n    Subchannel subchannel = result.getSubchannel();\n    if (subchannel != null) {\n      transport = ((TransportProvider) subchannel.getInternalSubchannel()).obtainActiveTransport();\n    } else {\n      transport = null;\n    }\n    if (transport != null) {\n      final ClientStreamTracer.Factory streamTracerFactory = result.getStreamTracerFactory();","sourceCodeStart":684,"sourceCodeEnd":720,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/core/src/main/java/io/grpc/internal/GrpcUtil.java#L684-L720","documentation":"gRPC timeout header values are numeric amounts followed by a unit character (n/u/m/S/M/H). GrpcUtil's timeout parser converts these to nanoseconds, but if the trailing unit character is not one of the supported units, it throws IllegalArgumentException(\"Invalid timeout unit: %s\").","triggerScenarios":"Sending or receiving a grpc-timeout value whose unit suffix is not n, u, m, S, M, or H - e.g. '100ms', '5s' (lowercase seconds), or a bare number without a unit - when the marshaller parses the ASCII string.","commonSituations":"Custom clients/proxies emitting lowercase unit letters or ISO-style 'ms' units; intermediary middleware rewriting the timeout header incorrectly; hand-rolled Deadline encoding in tests.","solutions":["Emit gRPC-conformant timeouts with exactly one of the unit suffixes: n (ns), u (µs), m (ms), S, M, or H - e.g. \"100m\" not \"100ms\".","Produce the header via Deadline/Deadline.Ticker APIs (e.g. deadline.timeRemaining(TimeUnit.NANOSECONDS) with a unit suffix) instead of manual formatting.","Check the component that writes the timeout header (proxy, interceptor, custom marshaller) and fix its unit mapping."],"exampleFix":"// before\nString timeout = duration.toMillis() + \"ms\";\n// after\nString timeout = duration.toMillis() + \"m\"; // gRPC unit for millis","handlingStrategy":"validation","validationCode":"String s = timeoutString;\nif (!s.matches(\"^\\\\d+[nSumMH]$\")) throw new IllegalArgumentException(\"Invalid grpc-timeout: \" + s);","typeGuard":null,"tryCatchPattern":"try {\n  long nanos = GrpcUtil.TIMER_SERVICE.decodeTimeout(value);\n} catch (IllegalArgumentException e) {\n  // apply default deadline\n}","preventionTips":["Use Deadline APIs to generate timeout header values.","Only emit unit suffixes n, u, m, S, M, H (uppercase S/M/H, lowercase n/u/m).","Audit proxies/interceptors that rewrite the grpc-timeout header."],"tags":["grpc","timeout","header","parsing"],"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"}