{"record":{"id":"dac84f90af859490","repo":"zylon-ai/private-gpt","slug":"search-query-cannot-be-empty","errorCode":null,"errorMessage":"Search query cannot be empty","messagePattern":"Search query cannot be empty","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"private_gpt/components/web/web_search/providers/brave.py","lineNumber":87,"sourceCode":"            result_filter,\n            safesearch,\n            freshness,\n            spellcheck,\n            language,\n        )\n\n        # 3. Parser response\n        return await asyncio.to_thread(self._parse_response, response_data)\n\n    async def validate(self) -> None:\n        if not self._api_key or not self._api_key.strip():\n            raise ValueError(\"Brave Search API key is not configured\")\n\n    def _validate_query_params(\n        self, query: str, num_links: int, offset: int\n    ) -> tuple[str, int, int]:\n        if not query or not query.strip():\n            raise ValueError(\"Search query cannot be empty\")\n\n        normalized_num_links = max(1, min(20, num_links))  # Brave allows 1-20\n        if normalized_num_links != num_links:\n            logger.warning(\n                f\"Num_links {num_links} outside valid range [1,20], clamped to {normalized_num_links}\"\n            )\n\n        if offset < 0:\n            raise ValueError(\"Offset cannot be negative\")\n\n        return query, normalized_num_links, offset\n\n    async def _execute_http_request(\n        self,\n        query: str,\n        num_links: int,\n        offset: int,\n        result_filter: str,","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/components/web/web_search/providers/brave.py#L69-L105","documentation":"ValueError from BraveSearchProvider._validate_query_params: the query passed to search()/make_query is None, empty, or only whitespace. This is client-side validation before the Brave API is called, because Brave would reject a blank q parameter anyway.","triggerScenarios":"Calling WebSearchService.search('') or search('   '); a caller building the query from user input that arrived empty (blank chat turn, stripped template); passing query=None through **kwargs paths that skip earlier null checks.","commonSituations":"LLM tool-calling flows where the model emits an empty query argument; frontends forwarding a search box with no text; whitespace-only strings after trimming user input.","solutions":["Guard at the call site: skip the search when the query is blank instead of calling the API.","Trim and validate user/model-provided query strings before dispatch.","If the query legitimately came back empty from an LLM tool call, fix the tool schema to require a non-empty string."],"exampleFix":"# before\nresults = await web_search.search(query)\n\n# after\nif not query or not query.strip():\n    return []\nresults = await web_search.search(query.strip())","handlingStrategy":"validation","validationCode":"def valid_search_query(q: str | None) -> bool:\n    return bool(q and q.strip())\n\nif not valid_search_query(query):\n    return []  # skip search instead of raising","typeGuard":"def is_empty_query_error(exc: BaseException) -> bool:\n    return isinstance(exc, ValueError) and str(exc) == 'Search query cannot be empty'","tryCatchPattern":"try:\n    results = await provider.make_query(query, num_links)\nexcept ValueError as e:\n    if str(e) == 'Search query cannot be empty':\n        return []\n    raise","preventionTips":["Trim and reject blank queries at the UI/API boundary.","In LLM tool schemas, mark the query argument minLength=1.","Add unit tests for empty and whitespace-only query strings."],"tags":["validation","input","brave","web-search"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}