Skip to content

go.http_missing_timeout

Stability High Common in Incidents

Detects HTTP client usage without explicit timeout configuration.

HTTP requests without timeouts can hang indefinitely:

  • Connection pool exhaustion — Stuck requests hold connections
  • Goroutine leaks — Waiting goroutines accumulate
  • Cascade failures — One slow upstream brings down your service
  • Unresponsive service — All workers blocked waiting

The default http.Client has no timeout. This is a dangerous default.

// ❌ Before
client := &http.Client{}
resp, err := client.Get(url)
// Also bad: using http.Get directly
resp, err := http.Get(url)

If the server never responds, these calls wait forever.

// ✅ After
client := &http.Client{
Timeout: 30 * time.Second,
}
resp, err := client.Get(url)

After 30 seconds, the request fails with a timeout error.

  • &http.Client{} without Timeout field
  • http.Get(), http.Post(), etc. (use default client)
  • Client with Transport but no timeout
  • Missing context deadline on requests

Unfault can add Timeout: 30 * time.Second to HTTP client initialization when configuring a default client.

// Overall request timeout
client := &http.Client{
Timeout: 30 * time.Second,
}
// Fine-grained control with Transport
client := &http.Client{
Timeout: 30 * time.Second,
Transport: &http.Transport{
DialContext: (&net.Dialer{
Timeout: 5 * time.Second, // Connection timeout
KeepAlive: 30 * time.Second,
}).DialContext,
TLSHandshakeTimeout: 5 * time.Second,
ResponseHeaderTimeout: 10 * time.Second,
IdleConnTimeout: 90 * time.Second,
},
}
// Context-based timeout (per-request)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
resp, err := client.Do(req)