grpc/grpc-go · error
malformed grpc-timeout: %v
Error message
malformed grpc-timeout: %v
What it means
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.
Source
Thrown at internal/transport/handler_server.go:109
}
st := &serverHandlerTransport{
rw: w,
req: r,
closedCh: make(chan struct{}),
writes: make(chan func()),
peer: p,
contentType: contentType,
contentSubtype: contentSubtype,
stats: stats,
bufferPool: bufferPool,
}
st.logger = prefixLoggerForServerHandlerTransport(st)
if v := r.Header.Get("grpc-timeout"); v != "" {
to, err := decodeTimeout(v)
if err != nil {
msg := fmt.Sprintf("malformed grpc-timeout: %v", err)
http.Error(w, msg, http.StatusBadRequest)
return nil, status.Error(codes.Internal, msg)
}
st.timeoutSet = true
st.timeout = to
}
metakv := []string{"content-type", contentType}
if r.Host != "" {
metakv = append(metakv, ":authority", r.Host)
}
for k, vv := range r.Header {
k = strings.ToLower(k)
if isReservedHeader(k) && !isWhitelistedHeader(k) {
continue
}
for _, v := range vv {
v, err := decodeMetadataHeader(k, v)
if err != nil {View on GitHub (pinned to 03255a9237)
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.
Example fix
// before (malformed header injected by a proxy) // grpc-timeout: 5000 // server logs: malformed grpc-timeout // after: send a well-formed timeout, or omit it // grpc-timeout: 5000m (5000 milliseconds) // Prefer setting it client-side: ctx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() conn.Invoke(ctx, "/svc/Method", req, resp)
Defensive patterns
Strategy: validation
Validate before calling
// Validate a grpc-timeout value before forwarding (edge/proxy)
import "regexp"
var grpcTimeoutRe = regexp.MustCompile(`^[0-9]{1,8}[HMSmun]$`)
func validGrpcTimeout(v string) bool { return grpcTimeoutRe.MatchString(v) }
// if !validGrpcTimeout(h.Get("grpc-timeout")) { h.Del("grpc-timeout") } Try / catch
// NewServerHandlerTransport returns this as an error; handle it
st, err := transport.NewServerHandlerTransport(w, r, stats, pool)
if err != nil {
// already wrote HTTP 400/500 to w; just abort the handler
return
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- gRPC requires a ResponseWriter supporting http.Flusher
- malformed binary metadata %q in header %q: %v
- grpc: timed out when dialing
- credentials: rawConn is dispatched out of gRPC
- invalid gRPC request method %q
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/befaf199eecb5138.
Report an issue: GitHub.