{"record":{"id":"953c80d46d00243b","repo":"grpc/grpc-go","slug":"transport-timeout-unit-is-not-recognized-q","errorCode":null,"errorMessage":"transport: timeout unit is not recognized: %q","messagePattern":"transport: timeout unit is not recognized: %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/transport/http_util.go","lineNumber":200,"sourceCode":"\t\treturn time.Nanosecond, true\n\tdefault:\n\t}\n\treturn\n}\n\nfunc decodeTimeout(s string) (time.Duration, error) {\n\tsize := len(s)\n\tif size < 2 {\n\t\treturn 0, fmt.Errorf(\"transport: timeout string is too short: %q\", s)\n\t}\n\tif size > 9 {\n\t\t// Spec allows for 8 digits plus the unit.\n\t\treturn 0, fmt.Errorf(\"transport: timeout string is too long: %q\", s)\n\t}\n\tunit := timeoutUnit(s[size-1])\n\td, ok := timeoutUnitToDuration(unit)\n\tif !ok {\n\t\treturn 0, fmt.Errorf(\"transport: timeout unit is not recognized: %q\", s)\n\t}\n\tt, err := strconv.ParseUint(s[:size-1], 10, 64)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\tconst maxHours = math.MaxInt64 / uint64(time.Hour)\n\tif d == time.Hour && t > maxHours {\n\t\t// This timeout would overflow math.MaxInt64; clamp it.\n\t\treturn time.Duration(math.MaxInt64), nil\n\t}\n\treturn d * time.Duration(t), nil\n}\n\nconst (\n\tspaceByte   = ' '\n\ttildeByte   = '~'\n\tpercentByte = '%'\n)","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/transport/http_util.go#L182-L218","documentation":"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.","triggerScenarios":"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'.","commonSituations":"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.","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."],"exampleFix":"// before (broken): multi-char unit 'ms'\ngrpc-timeout: \"1000ms\"\n\n// after (valid): single-char unit 'm' for milliseconds\ngrpc-timeout: \"1000m\"","handlingStrategy":"validation","validationCode":"// Validate the timeout unit character\nfunc validateGrpcTimeoutUnit(s string) error {\n    if len(s) < 2 { return fmt.Errorf(\"too short\") }\n    switch s[len(s)-1] {\n    case 'H', 'M', 'S', 'm', 'u', 'n':\n        return nil\n    default:\n        return fmt.Errorf(\"unrecognized unit: %q\", string(s[len(s)-1]))\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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.)."],"tags":["transport","http2","timeout","header-parsing","network","protocol-violation"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}