Almaatla Claude commited on
Commit
d341a7a
·
unverified ·
1 Parent(s): cd869cb

Fix DuckDuckGo backend silently returning empty results (#2)

Browse files

query_ddg_search() didn't raise when the duckduckgo_search library got
blocked/rate-limited and parsed zero results instead of throwing. This made
/serp/search_duck report {"error": null, "results": []} on failure, and
worse, made the /serp/search fallback chain (_search_one) treat DDG's empty
return as a success and never try Brave or Bing — the reason /serp/search
was returning "All backends are rate-limited." even when Bing worked fine
on its own. Now an empty DDG result raises, so both endpoints behave
correctly.


Claude-Session: https://claude.ai/code/session_012sXQyRk3EZHbYHas8fQsiS

Co-authored-by: Claude <noreply@anthropic.com>

Files changed (1) hide show
  1. serp.py +17 -0
serp.py CHANGED
@@ -50,6 +50,20 @@ class BrowserUnavailableError(Exception):
50
  super().__init__("Playwright browser is not available (it failed to start at startup).")
51
 
52
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  _PLAYWRIGHT_CONCURRENCY_SEMAPHORE = Semaphore(PLAYWRIGHT_CONCURRENCY_LIMIT)
54
 
55
 
@@ -260,6 +274,9 @@ async def query_ddg_search(q: str, n_results: int = 10):
260
  results.append(
261
  {"title": result["title"], "body": result["body"], "href": result["href"]})
262
 
 
 
 
263
  return results
264
 
265
 
 
50
  super().__init__("Playwright browser is not available (it failed to start at startup).")
51
 
52
 
53
+ class DuckDuckGoBlockedException(Exception):
54
+ """Raised when DuckDuckGo returns zero results.
55
+
56
+ The duckduckgo_search library doesn't always raise when its request is
57
+ blocked/rate-limited — it can also just parse zero results from the
58
+ anti-bot response page and return an empty list. Since callers (the
59
+ `/serp/search` fallback chain in particular) rely on an exception to know
60
+ a backend failed, treat an empty result as a failure too.
61
+ """
62
+
63
+ def __init__(self, *args):
64
+ super().__init__("DuckDuckGo returned no results, likely blocked or rate-limited")
65
+
66
+
67
  _PLAYWRIGHT_CONCURRENCY_SEMAPHORE = Semaphore(PLAYWRIGHT_CONCURRENCY_LIMIT)
68
 
69
 
 
274
  results.append(
275
  {"title": result["title"], "body": result["body"], "href": result["href"]})
276
 
277
+ if not results:
278
+ raise DuckDuckGoBlockedException()
279
+
280
  return results
281
 
282