zylon-ai/private-gpt · error · ValueError
Brave Search API invalid token ({error_message})
Error message
Brave Search API invalid token ({error_message}) What it means
ValueError raised when Brave Search returns HTTP 400 and the provider maps it to an invalid-token condition. The Brave API rejects malformed or unauthorized requests with 400 plus an error body; the provider surfaces the body's detail in the message so the exact API complaint is visible.
Source
Thrown at private_gpt/components/web/web_search/providers/brave.py:244
quota_header = response.headers.get("x-ratelimit-remaining")
if quota_header is not None and quota_header.strip() == "0":
raise QuotaConsumed(
"Brave Search API quota exhausted (x-ratelimit-remaining=0)"
)
status_code = response.status
if status_code < 400:
return
error = response_data.get("error", "Unknown error")
error_message = self._extract_error_message(error)
if status_code == 429:
logger.debug(f"Brave Search API rate limit exceeded: {error_message}")
raise RateLimitExceeded(
f"Brave Search API rate limit exceeded: {error_message}"
)
elif status_code == 400:
raise ValueError(f"Brave Search API invalid token ({error_message})")
elif status_code >= 500:
raise Exception(f"Brave Search API server error: {error_message}")
else:
raise Exception(f"Brave Search API error ({status_code}): {error_message}")
def _build_request_params(
self,
query: str,
num_links: int,
offset: int,
result_filter: str,
safesearch: bool,
freshness: str | None,
spellcheck: bool,
language: str | None,
) -> dict[str, Any]:
params = {
"q": query.strip(),View on GitHub (pinned to 4a030776a3)
Solutions
- Verify the key at account.brave.com and re-paste it exactly (no quotes/spaces) into web_search.brave.api_key.
- Confirm the key has the Search API product enabled and is not suspended.
- Reproduce with curl -H 'X-Subscription-Token: <key>' to see Brave's raw response.
- If the body indicates a parameter problem rather than auth, check the query params being sent (country, language, freshness formatting).
Example fix
# verify key before wiring it in
curl -s -o /dev/null -w '%{http_code}' \
-H 'X-Subscription-Token: $BRAVE_API_KEY' \
'https://api.search.brave.com/res/v1/web/search?q=test' Defensive patterns
Strategy: validation
Validate before calling
import aiohttp
async def brave_key_ok(api_key: str) -> bool:
async with aiohttp.ClientSession() as s:
async with s.get(
'https://api.search.brave.com/res/v1/web/search?q=ping',
headers={'X-Subscription-Token': api_key},
) as r:
return r.status < 400 Type guard
def is_brave_invalid_token(exc: BaseException) -> bool:
return isinstance(exc, ValueError) and 'Brave Search API invalid token' in str(exc) Try / catch
try:
results = await provider.make_query(q, num_links)
except ValueError as e:
if 'invalid token' in str(e):
raise RuntimeError('Brave API key rejected — regenerate and update settings') from e
raise Prevention
- Smoke-test the key with a one-line curl before deploying.
- Store keys in a secret manager; never paste with surrounding whitespace/quotes.
- Alert on 400s specifically — they indicate config, not load.
When it happens
Trigger: API key that is wrong, revoked, or contains whitespace/quotes from config templating; a malformed request (bad parameter encoding) that Brave reports as 400; key from a different Brave product (e.g. images/news plan) used on the web search endpoint.
Common situations: Typo'd or expired key pasted into settings.yaml; CI using a placeholder key; key truncated by env-var length limits or shell quoting.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Brave Search API key is not configured
- Invalid system specification (dict): {system}
- Search query cannot be empty
- Offset cannot be negative
- Brave Search API quota exhausted (x-ratelimit-remaining=0)
AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15).
Data as JSON: /api/errors/b291d01d4fd7761c.
Report an issue: GitHub.