{"record":{"id":"a2304133e2ad76ce","repo":"ScrapeGraphAI/Scrapegraph-ai","slug":"search-request-timed-out-after-timeout-seconds","errorCode":null,"errorMessage":"Search request timed out after {timeout} seconds","messagePattern":"Search request timed out after (.+?) seconds","errorType":"exception","errorClass":"TimeoutError","httpStatus":null,"severity":"error","filePath":"scrapegraphai/utils/research_web.py","lineNumber":239,"sourceCode":"        elif config.search_engine == \"bing\":\n            results = _search_bing(\n                config.query, config.max_results, config.timeout, formatted_proxy\n            )\n\n        elif config.search_engine == \"searxng\":\n            results = _search_searxng(\n                config.query, config.max_results, config.port, config.timeout\n            )\n\n        elif config.search_engine == \"serper\":\n            results = _search_serper(\n                config.query, config.max_results, config.serper_api_key, config.timeout\n            )\n\n        return filter_pdf_links(results)\n\n    except requests.Timeout:\n        raise TimeoutError(f\"Search request timed out after {timeout} seconds\")\n    except requests.RequestException as e:\n        raise SearchRequestError(f\"Search request failed: {str(e)}\")\n    except ValueError as e:\n        raise SearchConfigError(f\"Invalid search configuration: {str(e)}\")\n\n\ndef _search_duckduckgo(\n    query: str, max_results: int, proxy: Optional[str] = None\n) -> List[str]:\n    \"\"\"\n    Helper function for DuckDuckGo search using the ``ddgs`` package.\n\n    The ``duckduckgo-search`` package was renamed to ``ddgs``; recent\n    ``langchain-community`` releases import ``from ddgs import DDGS``, which\n    silently broke the previous langchain-based implementation. This calls\n    ``ddgs`` directly so results no longer depend on parsing a formatted string.\n\n    Args:","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/ScrapeGraphAI/Scrapegraph-ai/blob/532dfffbf6ee823a6c9cf8cfedc24a93bf026780/scrapegraphai/utils/research_web.py#L221-L257","documentation":"Raised by search_on_web when the underlying HTTP search request exceeds the configured timeout and requests.Timeout is caught. It is re-raised as a built-in TimeoutError so callers can handle search latency uniformly across engines. The timeout value comes from the SearchConfig passed to search_on_web.","triggerScenarios":"Calling search_on_web (directly or via the research/execute graph step) with a short config.timeout while the search engine endpoint (Google/Bing/SearXNG/Serper) is slow, unreachable, or blocked by a proxy/firewall.","commonSituations":"Corporate proxies or restricted networks slowing requests; setting timeout too low (default few seconds); rate-limited or throttled search endpoints; running in CI without network access.","solutions":["Increase config.timeout (e.g. 15-30 seconds) and retry","Check network/proxy connectivity to the search endpoint","Wrap search_on_web in a retry with exponential backoff for transient slowness","If consistently timing out, switch to a faster engine (e.g. serper with a valid API key)"],"exampleFix":"// before\nresults = search_on_web(SearchConfig(query=\"x\", timeout=3))\n// after\nresults = search_on_web(SearchConfig(query=\"x\", timeout=30))","handlingStrategy":"retry","validationCode":"if config.timeout < 10:\n    config.timeout = 15  # raise floor before calling","typeGuard":null,"tryCatchPattern":"try:\n    results = search_on_web(config)\nexcept TimeoutError:\n    config.timeout *= 2\n    results = search_on_web(config)","preventionTips":["Set a realistic timeout (>=15s) for search backends","Use retry with exponential backoff for TimeoutError","Monitor typical search latency in your environment"],"tags":["network","timeout","web-search"],"backgroundTag":"request-timeout","analyzedSha":"532dfffbf6ee823a6c9cf8cfedc24a93bf026780","analyzedAt":"2026-08-28T15:19:38.821Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}