Skip to content

go.unbounded_retry

Stability High

Detects retry patterns that don’t have proper bounds, which can cause infinite loops on permanent failures.

Unbounded retries cause:

  • Infinite loops — Permanent failures never stop retrying
  • Resource exhaustion — CPU and connections consumed by retries
  • DoS on dependencies — Overwhelming already-struggling services
  • Extended outages — Retries prevent recovery
// ❌ Before (unbounded)
func fetchData() error {
for {
if err := callAPI(); err == nil {
return nil
}
time.Sleep(time.Second)
}
}
// ✅ After (bounded with backoff)
func fetchData() error {
maxRetries := 5
backoff := time.Second
for i := 0; i < maxRetries; i++ {
if err := callAPI(); err == nil {
return nil
}
time.Sleep(backoff)
backoff *= 2 // Exponential backoff
if backoff > time.Minute {
backoff = time.Minute
}
}
return errors.New("max retries exceeded")
}
  • for {} loops with retry patterns
  • Missing max retry count
  • Missing backoff delays
  • Retries without jitter

Unfault generates patches using retry libraries:

import "github.com/cenkalti/backoff/v4"
func fetchData() error {
operation := func() error {
return callAPI()
}
b := backoff.NewExponentialBackOff()
b.MaxElapsedTime = 2 * time.Minute
b.MaxInterval = 30 * time.Second
return backoff.Retry(operation, b)
}