shareAI-lab/learn-claude-code · error · RuntimeError

Max retries ({MAX_RETRIES}) exceeded

Error message

Max retries ({MAX_RETRIES}) exceeded

What it means

The API-call retry loop handles overloaded/529 responses by sleeping with backoff and retrying, up to MAX_RETRIES attempts. If the provider is still returning overload errors after the final attempt, the loop exits and raises this RuntimeError — the caller has exhausted the configured retry budget against a persistently saturated upstream.

Source

Thrown at s15_integrated_harness/code.py:2071

            if "ratelimit" in name or "429" in msg:
                delay = retry_delay(attempt)
                print(f"  \033[33m[429] retry {attempt + 1}/{MAX_RETRIES} "
                      f"after {delay:.1f}s\033[0m")
                time.sleep(delay)
                continue
            if "overloaded" in name or "529" in msg or "overloaded" in msg:
                state.consecutive_529 += 1
                if state.consecutive_529 >= MAX_CONSECUTIVE_529 and FALLBACK_MODEL:
                    state.current_model = FALLBACK_MODEL
                    state.consecutive_529 = 0
                    print(f"  \033[31m[529] switching to {FALLBACK_MODEL}\033[0m")
                delay = retry_delay(attempt)
                print(f"  \033[33m[529] retry {attempt + 1}/{MAX_RETRIES} "
                      f"after {delay:.1f}s\033[0m")
                time.sleep(delay)
                continue
            raise
    raise RuntimeError(f"Max retries ({MAX_RETRIES}) exceeded")


def is_prompt_too_long_error(e: Exception) -> bool:
    msg = str(e).lower()
    return (("prompt" in msg and "long" in msg)
            or "context_length_exceeded" in msg
            or "max_context_window" in msg)


# -- Background Tasks --

# Slow tools return a placeholder tool_result immediately. Their real output is
# later injected as a task_notification, so the main loop can keep moving.
_bg_counter = 0
background_tasks: dict[str, dict] = {}
background_results: dict[str, str] = {}
background_lock = threading.Lock()

View on GitHub (pinned to 985456f4ad)

Solutions

  1. Wait and retry at a coarser cadence (the incident is upstream); space out requests to reduce concurrent load.
  2. Raise MAX_RETRIES and/or the backoff curve (retry_delay) in config so the loop spans the incident.
  3. Configure a healthy FALLBACK_MODEL on a different provider/family so the 529 switch actually lands somewhere available.
  4. If self-hosting the gateway, check its rate limits — sustained 529-like responses can be your own proxy shedding load.

Example fix

// before
MAX_RETRIES = 3

// after
MAX_RETRIES = 8  # span typical overload windows; backoff grows per attempt
Defensive patterns

Strategy: retry

Try / catch

try:
    response = call_api_with_retries()
except RuntimeError as e:
    if "Max retries" in str(e):
        schedule_retry_later(cooldown_minutes=10)  # coarse outer retry
        return "API overloaded; queued retry"
    raise

Prevention

When it happens

Trigger: Anthropic/API provider returning HTTP 529 or 'overloaded_error' for every attempt in the window; MAX_RETRIES set low while an incident is ongoing; a fallback model also overloaded (switching to FALLBACK_MODEL after MAX_CONSECUTIVE_529 doesn't help if it is saturated too); retry_delay backoff shorter than the incident.

Common situations: Provider capacity incidents at peak hours; small MAX_RETRIES/MAX_CONSECUTIVE_529 defaults in stress tests; bursty fan-out workloads from many agents sharing one key.

Related errors


AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14). Data as JSON: /api/errors/f7b38440256fec86. Report an issue: GitHub.