{"record":{"id":"92cf394d7314dca4","repo":"grpc/grpc-go","slug":"transport-timeout-string-is-too-short-q","errorCode":null,"errorMessage":"transport: timeout string is too short: %q","messagePattern":"transport: timeout string is too short: %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/transport/http_util.go","lineNumber":191,"sourceCode":"\tcase minute:\n\t\treturn time.Minute, true\n\tcase second:\n\t\treturn time.Second, true\n\tcase millisecond:\n\t\treturn time.Millisecond, true\n\tcase microsecond:\n\t\treturn time.Microsecond, true\n\tcase nanosecond:\n\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","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/transport/http_util.go#L173-L209","documentation":"Fires in decodeTimeout (http_util.go:191) when the grpc-timeout header value passed to the server has fewer than 2 characters. Per the gRPC over HTTP/2 spec, the timeout is encoded as <digits><unit>, so the shortest valid value is one digit plus a unit (e.g. \"1S\"). A shorter value cannot contain both a number and a unit and is malformed.","triggerScenarios":"An inbound grpc-timeout metadata value of length 0 or 1 reaches decodeTimeout. Produced by a client/proxy that sets an empty or single-char timeout header, or that truncates it. Since gRPC clients normally emit well-formed timeouts, this usually points to a hand-crafted caller, a buggy intermediary, or header corruption.","commonSituations":"A proxy/LB that rewrites or truncates grpc-timeout; a non-gRPC client (raw HTTP/2) setting the header incorrectly; a middleware that clears headers under some path; fuzzed or malformed traffic.","solutions":["Identify the caller setting the grpc-timeout header and fix it to the spec format: integer digits followed by a unit (H, M, S, m, u, n).","Inspect intermediary proxies/LBs/service meshes for header rewriting that truncates grpc-timeout.","If you control the client, rely on context deadlines (gRPC encodes them automatically) rather than setting the header by hand."],"exampleFix":"// before: hand-set, truncated header\n// metadata: {\"grpc-timeout\": \"\"}\n\n// after: let gRPC derive it from the context deadline\nctx, cancel := context.WithTimeout(ctx, 5*time.Second)\ndefer cancel()\nresp, err := client.Method(ctx, req)   // gRPC emits e.g. \"5S\"","handlingStrategy":"validation","validationCode":"// If you build grpc-timeout manually, ensure length >= 2 (digits + unit).\nfunc encodeGrpcTimeout(d time.Duration) (string, error) {\n    if d < 0 {\n        return \"\", fmt.Errorf(\"negative timeout\")\n    }\n    // prefer gRPC's own encoding; this is illustrative.\n    return fmt.Sprintf(\"%dS\", int64(d.Seconds())), nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Let gRPC encode grpc-timeout from context.WithTimeout rather than setting the header.","Audit intermediaries that might truncate or clear the header."],"tags":["transport","http2","timeout","metadata","protocol-violation"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}