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

  1. Inspect the raw grpc-timeout header value to identify the incorrect unit character.
  2. Fix the client to use single-character gRPC timeout units: H, M, S, m, u, n.
  3. 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

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

Related errors


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/953c80d46d00243b. Report an issue: GitHub.