grpc/grpc-go · error

transport: timeout string is too short: %q

Error message

transport: timeout string is too short: %q

What it means

This error occurs in decodeTimeout when the grpc-timeout HTTP/2 header value is shorter than 2 characters. The gRPC timeout format requires at least one digit followed by a unit character (e.g., '1S'), so a 0- or 1-character string cannot be parsed.

Source

Thrown at internal/transport/http_util.go:191

	case minute:
		return time.Minute, true
	case second:
		return time.Second, true
	case millisecond:
		return time.Millisecond, true
	case microsecond:
		return time.Microsecond, true
	case nanosecond:
		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

View on GitHub (pinned to 03255a9237)

Solutions

  1. Inspect the grpc-timeout header on the offending request using network tracing (e.g., Wireshark with HTTP/2 dissection).
  2. Fix or upgrade the client/proxy that produces the truncated header.
  3. If you control the client, ensure context deadlines are set properly so grpc-timeout is well-formed.

Example fix

// before (broken): empty or single-char timeout header sent by client
metadata: {"grpc-timeout": ""}

// after (valid): client sets a proper deadline
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
// grpc-go encodes this as "5000m" (5 seconds in millis)
Defensive patterns

Strategy: validation

Validate before calling

// Validate a grpc-timeout header value before processing
func validateGrpcTimeout(s string) error {
    if len(s) < 2 {
        return fmt.Errorf("timeout too short: needs >=1 digit + unit")
    }
    return nil
}

Try / catch

// On the server side, malformed grpc-timeout results in a stream abort
// with codes.Internal. Handle gracefully:
if status.Code(err) == codes.Internal {
    if strings.Contains(err.Error(), "malformed grpc-timeout") {
        log.Printf("client sent invalid timeout header")
    }
}

Prevention

When it happens

Trigger: An incoming gRPC request (or the client side decoding a server-sent timeout) has a grpc-timeout header with fewer than 2 bytes. This is typically caused by a malformed peer or an intermediary (proxy/LB) corrupting the header.

Common situations: A non-gRPC client or buggy proxy sends an empty or truncated grpc-timeout header; interoperability issues with an HTTP/2 implementation that strips the header value; or a load balancer that mangles header values.

Understand the failure class

Related errors


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