{"record":{"id":"b291d01d4fd7761c","repo":"zylon-ai/private-gpt","slug":"brave-search-api-invalid-token-error-message","errorCode":null,"errorMessage":"Brave Search API invalid token ({error_message})","messagePattern":"Brave Search API invalid token \\((.+?)\\)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"private_gpt/components/web/web_search/providers/brave.py","lineNumber":244,"sourceCode":"        quota_header = response.headers.get(\"x-ratelimit-remaining\")\n        if quota_header is not None and quota_header.strip() == \"0\":\n            raise QuotaConsumed(\n                \"Brave Search API quota exhausted (x-ratelimit-remaining=0)\"\n            )\n\n        status_code = response.status\n        if status_code < 400:\n            return\n\n        error = response_data.get(\"error\", \"Unknown error\")\n        error_message = self._extract_error_message(error)\n        if status_code == 429:\n            logger.debug(f\"Brave Search API rate limit exceeded: {error_message}\")\n            raise RateLimitExceeded(\n                f\"Brave Search API rate limit exceeded: {error_message}\"\n            )\n        elif status_code == 400:\n            raise ValueError(f\"Brave Search API invalid token ({error_message})\")\n        elif status_code >= 500:\n            raise Exception(f\"Brave Search API server error: {error_message}\")\n        else:\n            raise Exception(f\"Brave Search API error ({status_code}): {error_message}\")\n\n    def _build_request_params(\n        self,\n        query: str,\n        num_links: int,\n        offset: int,\n        result_filter: str,\n        safesearch: bool,\n        freshness: str | None,\n        spellcheck: bool,\n        language: str | None,\n    ) -> dict[str, Any]:\n        params = {\n            \"q\": query.strip(),","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/components/web/web_search/providers/brave.py#L226-L262","documentation":"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.","triggerScenarios":"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.","commonSituations":"Typo'd or expired key pasted into settings.yaml; CI using a placeholder key; key truncated by env-var length limits or shell quoting.","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)."],"exampleFix":"# verify key before wiring it in\ncurl -s -o /dev/null -w '%{http_code}' \\\n  -H 'X-Subscription-Token: $BRAVE_API_KEY' \\\n  'https://api.search.brave.com/res/v1/web/search?q=test'","handlingStrategy":"validation","validationCode":"import aiohttp\n\nasync def brave_key_ok(api_key: str) -> bool:\n    async with aiohttp.ClientSession() as s:\n        async with s.get(\n            'https://api.search.brave.com/res/v1/web/search?q=ping',\n            headers={'X-Subscription-Token': api_key},\n        ) as r:\n            return r.status < 400","typeGuard":"def is_brave_invalid_token(exc: BaseException) -> bool:\n    return isinstance(exc, ValueError) and 'Brave Search API invalid token' in str(exc)","tryCatchPattern":"try:\n    results = await provider.make_query(q, num_links)\nexcept ValueError as e:\n    if 'invalid token' in str(e):\n        raise RuntimeError('Brave API key rejected — regenerate and update settings') from e\n    raise","preventionTips":["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."],"tags":["brave","api-key","authentication","http-400"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}