{"record":{"id":"2ca810bdf13d726b","repo":"assafelovic/gpt-researcher","slug":"no-results-found-with-tavily-api-search","errorCode":null,"errorMessage":"No results found with Tavily API search.","messagePattern":"No results found with Tavily API search\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"gpt_researcher/retrievers/tavily/tavily_search.py","lineNumber":138,"sourceCode":"            site_domains = _SITE_OPERATOR_PATTERN.findall(query)\n            if site_domains:\n                query = _SITE_OPERATOR_PATTERN.sub(\"\", query).strip()\n                # Keep only the domain part (Tavily matches domains, not paths)\n                site_domains = [d.strip(\",\").split(\"/\")[0] for d in site_domains]\n                include_domains = list(dict.fromkeys(site_domains + (include_domains or [])))\n\n            # Search the query (Tavily rejects queries longer than 400 chars)\n            results = self._search(\n                query[:400],\n                search_depth=\"basic\",\n                max_results=max_results,\n                topic=self.topic,\n                include_domains=include_domains,\n            )\n            # API/proxy glitches can yield a list or scalar JSON body; only dict\n            # responses have a top-level \"results\" key we understand.\n            if not isinstance(results, dict):\n                raise Exception(\"No results found with Tavily API search.\")\n            sources = results.get(\"results\", [])\n            if not isinstance(sources, list) or not sources:\n                raise Exception(\"No results found with Tavily API search.\")\n            # Return the results. Guard each source against missing/None\n            # fields so a single malformed hit does not drop the whole page.\n            search_response = []\n            for obj in sources:\n                if not isinstance(obj, dict):\n                    continue\n                href = obj.get(\"url\")\n                if not href:\n                    continue\n                body = obj.get(\"content\") or obj.get(\"snippet\") or \"\"\n                search_response.append({\"href\": href, \"body\": body})\n        except Exception as e:\n            print(f\"Error: {e}. Failed fetching sources. Resulting in empty response.\")\n            search_response = []\n        return search_response","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/assafelovic/gpt-researcher/blob/6f998577d547b1e54ec662dac63583aa11e3b84b/gpt_researcher/retrievers/tavily/tavily_search.py#L120-L156","documentation":"After calling the Tavily search API, the retriever validates the shape of the response: Tavily is expected to return a JSON object (dict) with a top-level 'results' key. If the response is not a dict (e.g., a list or scalar JSON body, often due to API or proxy glitches), the code raises 'No results found with Tavily API search.' despite the HTTP call technically succeeding.","triggerScenarios":"Calling tavily_search's search() when the Tavily client returns a non-dict payload — for example a proxy returning a JSON array/scalar, an API format change, or a degraded response. The isinstance(results, dict) check fails and the generic 'no results' Exception is thrown.","commonSituations":"Corporate proxies or API gateways rewriting/mangling the response body; Tavily changing its response schema between SDK versions; empty or error payloads returned as lists; intermittent API glitches that are transient and succeed on retry.","solutions":["Retry the search — transient API/proxy glitches often resolve themselves.","Pin/upgrade the tavily-python package to a version whose response format matches this retriever's expectations (pip install -U tavily-python).","If behind a proxy, bypass it for api.tavily.com or fix the proxy's response rewriting.","Inspect the raw response by calling tavily_client.search(...) directly to see what body is actually returned.","Fall back to a different retriever (e.g., 'duckduckgo' or 'tavily'-alternative) if Tavily consistently returns malformed bodies."],"exampleFix":"# before\nresults = tavily_client.search(query)  # proxy returns [ ... ] (a list)\nretriever.search()  # raises: No results found with Tavily API search.\n\n# after\nresults = tavily_client.search(query)\nif not isinstance(results, dict):\n    results = {'results': results if isinstance(results, list) else []}  # normalize, then handle empty gracefully","handlingStrategy":"retry","validationCode":"# Pre-flight: call Tavily directly and confirm the response shape\nresp = tavily_client.search(query)\nassert isinstance(resp, dict) and isinstance(resp.get('results'), list), 'unexpected Tavily response shape'","typeGuard":"def is_tavily_response(v) -> bool:\n    return isinstance(v, dict) and isinstance(v.get('results'), list)","tryCatchPattern":"for attempt in range(3):\n    try:\n        return retriever.search()\n    except Exception as e:\n        if 'No results found' in str(e) and attempt < 2:\n            time.sleep(2 ** attempt)\n            continue\n        raise","preventionTips":["Pin the tavily-python version you tested against.","Exclude api.tavily.com from corporate proxies or verify proxy response bodies.","Wrap retriever calls with a retry-once wrapper for transient shape glitches.","Log the raw Tavily response when validation fails so root cause is visible."],"tags":["tavily","search-api","response-validation","proxy","retriever"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"6f998577d547b1e54ec662dac63583aa11e3b84b","analyzedAt":"2026-08-28T17:50:07.383Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}