crewAIInc/crewAI · error · RuntimeError
Brave Search API error (HTTP {status}): {body}
Error message
Brave Search API error (HTTP {status}): {body} What it means
BraveSearchTool's _raise_for_error() builds the final error for non-OK Brave API responses: it embeds the HTTP status and, when possible, the JSON error body (Brave returns helpful error payloads); if the body is not JSON it falls back to the first 500 chars of text. It is raised after retries are exhausted for retryable errors, or immediately for non-retryable ones (auth failures, quota exhaustion).
Source
Thrown at lib/crewai-tools/src/crewai_tools/tools/brave_search_tool/base.py:48
def _parse_error_body(resp: requests.Response) -> dict[str, Any] | None:
"""Extract the structured "error" object from a Brave API error response."""
try:
body = resp.json()
error = body.get("error")
return error if isinstance(error, dict) else None
except (ValueError, KeyError):
return None
def _raise_for_error(resp: requests.Response) -> None:
"""Brave Search API error responses contain helpful JSON payloads"""
status = resp.status_code
try:
body = json.dumps(resp.json())
except (ValueError, KeyError):
body = resp.text[:500]
raise RuntimeError(f"Brave Search API error (HTTP {status}): {body}")
def _is_retryable(resp: requests.Response) -> bool:
"""Return True for transient failures that are worth retrying.
* 429 + RATE_LIMITED — the per-second sliding window is full.
* 5xx — transient server-side errors.
Quota exhaustion (QUOTA_LIMITED, USAGE_LIMIT_EXCEEDED) is
explicitly excluded: retrying will never succeed until the billing
period resets.
"""
if resp.status_code == 429:
error = _parse_error_body(resp) or {}
return error.get("code") not in _QUOTA_CODES
return 500 <= resp.status_code < 600
View on GitHub (pinned to 754d7323be)
Solutions
- Read the embedded body: RATE_LIMITED means slow down (lower requests_per_second), QUOTA_LIMITED/USAGE_LIMITED means wait for the billing reset or upgrade the plan.
- For 401/422, regenerate the API key in the Brave dashboard and re-export BRAVE_API_KEY.
- If 5xx persists across retries, check https://status.brave.com and retry later with backoff.
- Reduce call volume: cache query results and reuse one tool instance so its per-instance rate limiter is effective.
Example fix
# before
results = tool._run("query")
# after
try:
results = tool._run("query")
except RuntimeError as e:
if "QUOTA_LIMITED" in str(e) or "USAGE_LIMITED" in str(e):
results = cached_results # quota errors never succeed on retry
else:
raise Defensive patterns
Strategy: try-catch
Type guard
def is_fatal_brave_error(err: RuntimeError) -> bool:
msg = str(err)
return "QUOTA_LIMITED" in msg or "USAGE_LIMITED" in msg or "HTTP 401" in msg or "HTTP 422" in msg Try / catch
try:
result = tool._run(query)
except RuntimeError as e:
if is_fatal_brave_error(e):
return fallback_results(query) # quota/auth errors never succeed on retry
if "HTTP 5" in str(e):
time.sleep(5) # tool already retried; one outer backoff for server errors
raise Prevention
- Parse the embedded JSON body string to branch: rate-limit vs quota vs auth vs 5xx each need different responses.
- Monitor quota consumption in the Brave dashboard and alert before exhaustion.
- Never retry QUOTA_LIMITED/USAGE_LIMITED — the tool deliberately excludes them from retryability.
When it happens
Trigger: 422/401 from an invalid or revoked BRAVE_API_KEY; 429 RATE_LIMITED persisting beyond the retry window; QUOTA_LIMITED / USAGE_LIMIT_EXCEEDED (explicitly non-retryable); 5xx that keeps failing across all retry attempts.
Common situations: Expired or wrong-plan API key; free tier monthly quota used up; sustained traffic above the per-second rate so every retry still lands in the full window; Brave-side incidents.
Related errors
- HTTP {response.status}: {response.reason}
- Trigger failed: {await trigger_response.text()}
- Project name '{name}' would generate invalid Python class na
- Failed to retrieve organization list: {e!s}
- Unable to fetch documentation from {docs_url}: {e}
AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15).
Data as JSON: /api/errors/ceb26eedf4c9c2e1.
Report an issue: GitHub.