{"record":{"id":"befaf199eecb5138","repo":"grpc/grpc-go","slug":"malformed-grpc-timeout-v","errorCode":null,"errorMessage":"malformed grpc-timeout: %v","messagePattern":"malformed grpc-timeout: (.+?)","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"internal/transport/handler_server.go","lineNumber":109,"sourceCode":"\t}\n\tst := &serverHandlerTransport{\n\t\trw:             w,\n\t\treq:            r,\n\t\tclosedCh:       make(chan struct{}),\n\t\twrites:         make(chan func()),\n\t\tpeer:           p,\n\t\tcontentType:    contentType,\n\t\tcontentSubtype: contentSubtype,\n\t\tstats:          stats,\n\t\tbufferPool:     bufferPool,\n\t}\n\tst.logger = prefixLoggerForServerHandlerTransport(st)\n\n\tif v := r.Header.Get(\"grpc-timeout\"); v != \"\" {\n\t\tto, err := decodeTimeout(v)\n\t\tif err != nil {\n\t\t\tmsg := fmt.Sprintf(\"malformed grpc-timeout: %v\", err)\n\t\t\thttp.Error(w, msg, http.StatusBadRequest)\n\t\t\treturn nil, status.Error(codes.Internal, msg)\n\t\t}\n\t\tst.timeoutSet = true\n\t\tst.timeout = to\n\t}\n\n\tmetakv := []string{\"content-type\", contentType}\n\tif r.Host != \"\" {\n\t\tmetakv = append(metakv, \":authority\", r.Host)\n\t}\n\tfor k, vv := range r.Header {\n\t\tk = strings.ToLower(k)\n\t\tif isReservedHeader(k) && !isWhitelistedHeader(k) {\n\t\t\tcontinue\n\t\t}\n\t\tfor _, v := range vv {\n\t\t\tv, err := decodeMetadataHeader(k, v)\n\t\t\tif err != nil {","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/transport/handler_server.go#L91-L127","documentation":"NewServerHandlerTransport (handler_server.go:53) parses the grpc-timeout header via decodeTimeout (http_util.go:188). If the header is present but malformed, it writes HTTP 400 and returns this error (codes.Internal wrapping the decode error). decodeTimeout fails when the value is too short (<2 chars), too long (>9 chars), has an unrecognized unit char, or the numeric part isn't a valid uint.","triggerScenarios":"A client or proxy sends a grpc-timeout header whose value does not match the gRPC timeout format: <digits><unit> where unit is one of H M S m u n. Examples: \"100\" (no unit), \"1X\" (bad unit), \"1234567890S\" (too long), \"abc\" (non-numeric).","commonSituations":"A non-gRPC client or a misbehaving proxy injecting a malformed grpc-timeout; a custom client building the header by hand instead of using the gRPC library; an intermediary that rewrites/truncates the header.","solutions":["Ensure the grpc-timeout header is produced by a compliant gRPC client library (set via context.WithTimeout/grpc timeout, not hand-crafted).","If a proxy sets grpc-timeout, validate it matches <1-8 digits><H|M|S|m|u|n> before forwarding.","Strip any malformed grpc-timeout at the proxy edge so the gRPC server treats the request as having no deadline."],"exampleFix":"// before (malformed header injected by a proxy)\n//   grpc-timeout: 5000\n// server logs: malformed grpc-timeout\n\n// after: send a well-formed timeout, or omit it\n//   grpc-timeout: 5000m  (5000 milliseconds)\n// Prefer setting it client-side:\nctx, cancel := context.WithTimeout(ctx, 5*time.Second)\ndefer cancel()\nconn.Invoke(ctx, \"/svc/Method\", req, resp)","handlingStrategy":"validation","validationCode":"// Validate a grpc-timeout value before forwarding (edge/proxy)\nimport \"regexp\"\nvar grpcTimeoutRe = regexp.MustCompile(`^[0-9]{1,8}[HMSmun]$`)\nfunc validGrpcTimeout(v string) bool { return grpcTimeoutRe.MatchString(v) }\n// if !validGrpcTimeout(h.Get(\"grpc-timeout\")) { h.Del(\"grpc-timeout\") }","typeGuard":null,"tryCatchPattern":"// NewServerHandlerTransport returns this as an error; handle it\nst, err := transport.NewServerHandlerTransport(w, r, stats, pool)\nif err != nil {\n    // already wrote HTTP 400/500 to w; just abort the handler\n    return\n}","preventionTips":["Always set deadlines via context.WithTimeout on the gRPC client, never by hand-crafting the header.","At any proxy edge, validate or strip non-conformant grpc-timeout headers.","Ensure intermediaries do not truncate or rewrite the timeout header."],"tags":["transport","http","timeout","grpc-go","handler"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}