grpc/grpc-java · error · IllegalArgumentException
Invalid timeout unit
Error message
Invalid timeout unit: %s
What it means
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").
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.
Example fix
// before String timeout = duration.toMillis() + "ms"; // after String timeout = duration.toMillis() + "m"; // gRPC unit for millis
Defensive patterns
Strategy: validation
Validate before calling
String s = timeoutString;
if (!s.matches("^\\d+[nSumMH]$")) throw new IllegalArgumentException("Invalid grpc-timeout: " + s); Try / catch
try {
long nanos = GrpcUtil.TIMER_SERVICE.decodeTimeout(value);
} catch (IllegalArgumentException e) {
// apply default deadline
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "invalid duration" / "failed to parse duration": why your timeout, interval, or TTL string is rejected and which formats each library accepts — this error's family across 32 libraries.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Illegal log config pattern:
- Illegal log config pattern
- A key manager is required
- A terminal HttpFilter must be the last filter
- Address is not an IP
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/6418fb9b6f5ad1cc.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/io/grpc/internal/GrpcUtil.java:702
checkArgument(serialized.length() > 0, "empty timeout");
checkArgument(serialized.length() <= 9, "bad timeout format");
long value = Long.parseLong(serialized.substring(0, serialized.length() - 1));
char unit = serialized.charAt(serialized.length() - 1);
switch (unit) {
case 'n':
return value;
case 'u':
return TimeUnit.MICROSECONDS.toNanos(value);
case 'm':
return TimeUnit.MILLISECONDS.toNanos(value);
case 'S':
return TimeUnit.SECONDS.toNanos(value);
case 'M':
return TimeUnit.MINUTES.toNanos(value);
case 'H':
return TimeUnit.HOURS.toNanos(value);
default:
throw new IllegalArgumentException(String.format("Invalid timeout unit: %s", unit));
}
}
}
/**
* Returns a transport out of a PickResult, or {@code null} if the result is "buffer".
*/
@Nullable
static ClientTransport getTransportFromPickResult(PickResult result, boolean isWaitForReady) {
final ClientTransport transport;
Subchannel subchannel = result.getSubchannel();
if (subchannel != null) {
transport = ((TransportProvider) subchannel.getInternalSubchannel()).obtainActiveTransport();
} else {
transport = null;
}
if (transport != null) {
final ClientStreamTracer.Factory streamTracerFactory = result.getStreamTracerFactory();View on GitHub (pinned to 64daddc1f3)