grpc/grpc-go · error
transport: timeout unit is not recognized: %q
Error message
transport: timeout unit is not recognized: %q
What it means
This error occurs in decodeTimeout when the last character of the grpc-timeout header is not a recognized timeout unit. Valid units are H (hour), M (minute), S (second), m (millisecond), u (microsecond), n (nanosecond). Any other trailing character causes this error.
Source
Thrown at internal/transport/http_util.go:200
return time.Nanosecond, true
default:
}
return
}
func decodeTimeout(s string) (time.Duration, error) {
size := len(s)
if size < 2 {
return 0, fmt.Errorf("transport: timeout string is too short: %q", s)
}
if size > 9 {
// Spec allows for 8 digits plus the unit.
return 0, fmt.Errorf("transport: timeout string is too long: %q", s)
}
unit := timeoutUnit(s[size-1])
d, ok := timeoutUnitToDuration(unit)
if !ok {
return 0, fmt.Errorf("transport: timeout unit is not recognized: %q", s)
}
t, err := strconv.ParseUint(s[:size-1], 10, 64)
if err != nil {
return 0, err
}
const maxHours = math.MaxInt64 / uint64(time.Hour)
if d == time.Hour && t > maxHours {
// This timeout would overflow math.MaxInt64; clamp it.
return time.Duration(math.MaxInt64), nil
}
return d * time.Duration(t), nil
}
const (
spaceByte = ' '
tildeByte = '~'
percentByte = '%'
)View on GitHub (pinned to 03255a9237)
Solutions
- Inspect the raw grpc-timeout header value to identify the incorrect unit character.
- Fix the client to use single-character gRPC timeout units: H, M, S, m, u, n.
- Check for intermediary proxies that rewrite or corrupt the grpc-timeout header.
Example fix
// before (broken): multi-char unit 'ms' grpc-timeout: "1000ms" // after (valid): single-char unit 'm' for milliseconds grpc-timeout: "1000m"
Defensive patterns
Strategy: validation
Validate before calling
// Validate the timeout unit character
func validateGrpcTimeoutUnit(s string) error {
if len(s) < 2 { return fmt.Errorf("too short") }
switch s[len(s)-1] {
case 'H', 'M', 'S', 'm', 'u', 'n':
return nil
default:
return fmt.Errorf("unrecognized unit: %q", string(s[len(s)-1]))
}
} Prevention
- Use grpc-go or another compliant library that encodes timeouts with single-character units.
- Never manually construct grpc-timeout headers; always use context.WithTimeout.
- Educate teams that gRPC timeout units are single chars (not 'ms', 'sec', etc.).
When it happens
Trigger: A peer sends a grpc-timeout header like "1000ms" or "5x" where the unit character is not one of {H, M, S, m, u, n}. Note that 'ms' is invalid — the correct encoding for milliseconds is a single 'm'.
Common situations: A non-compliant client encodes timeout using a multi-character unit suffix (e.g., "ms", "sec") instead of the single-character gRPC encoding, or a proxy/header-rewriting layer corrupts the unit byte.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- transport: timeout string is too long: %q
- transport: timeout string is too short: %q
- received an illegal stream id: %v. headers frame: %+v
- keepalive ping not acked within timeout %s
- received %d-bytes data exceeding the limit %d bytes
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/953c80d46d00243b.
Report an issue: GitHub.