infiniflow/ragflow · error · RuntimeError
SerpApi returned no organic_results.
Error message
SerpApi returned no organic_results.
What it means
Raised as RuntimeError by the Google (SerpApi) search tool when the SerpApi response dict lacks 'organic_results'. SerpApi signals an invalid API key, exhausted quota, or an empty result set through an 'error' field while omitting 'organic_results'; the tool surfaces that error message, and only falls back to the literal 'SerpApi returned no organic_results.' when neither key exists.
Source
Thrown at agent/tools/google.py:505
return ""
params = {"api_key": self._param.api_key, "engine": "google", "q": kwargs["q"], "google_domain": "google.com", "gl": self._param.country, "hl": self._param.language}
last_e = ""
for _ in range(self._param.max_retries + 1):
if self.check_if_canceled("Google processing"):
return
try:
search = GoogleSearch(params).get_dict()
if self.check_if_canceled("Google processing"):
return
# serpapi reports an invalid key, exhausted quota or an empty result
# set through an "error" field and omits "organic_results"; surface that
# message instead of raising a cryptic KeyError on the missing key.
if "organic_results" not in search:
raise RuntimeError(search.get("error", "SerpApi returned no organic_results."))
organic_results = search["organic_results"]
# a result may omit any of these; note the fallback of the "description"
# lookup is evaluated eagerly, so it has to be a .get() too or a result
# carrying a description but no snippet raises KeyError.
self._retrieve_chunks(
organic_results,
get_title=lambda r: r.get("title", ""),
get_url=lambda r: r.get("link", ""),
get_content=lambda r: r.get("about_this_result", {}).get("source", {}).get("description", r.get("snippet", "")),
)
self.set_output("json", organic_results)
return self.output("formalized_content")
except Exception as e:
if self.check_if_canceled("Google processing"):
return
last_e = eView on GitHub (pinned to 554fb1133a)
Solutions
- Read the RuntimeError text — 'Invalid API key' or 'Your searches are exhausted' tells you to fix the key or upgrade/top-up the plan at serpapi.com.
- Verify the key with a curl 'https://serpapi.com/search?q=test&api_key=KEY' and confirm the response contains organic_results.
- If the key is valid and quota remains, loosen the query (remove restrictive site:/filetype: filters, check gl/hl params) so organic results exist.
- Cache search responses to avoid burning quota on repeated agent runs.
Defensive patterns
Strategy: fallback
Validate before calling
def serpapi_key_ok(key: str) -> bool:
import requests
r = requests.get("https://serpapi.com/account", params={"api_key": key}, timeout=10)
return r.ok and r.json().get("account_rate_limit_per_hour", 0) >= 0 Try / catch
try:
return google_tool._invoke(query=q)
except RuntimeError as e:
if "organic_results" in str(e):
return "" # zero results: benign
log.error("serpapi: %s", e) # quota/key problem
return fallback_search(q) Prevention
- Monitor remaining SerpApi searches monthly quota via the account endpoint and alert before exhaustion.
- Treat 'no organic_results' with empty error text as empty-result, not failure.
- Cache queries so re-runs of the same agent don't burn quota.
When it happens
Trigger: GoogleSearch(params).get_dict() with an invalid/expired SERPAPI_API_KEY ('Your account is suspended' / 'Invalid API key'), a plan whose searches/month quota is exhausted, or a legitimate query that simply yields zero organic results (obscure query, num=0, heavy site: filtering).
Common situations: Agent canvas Google-search nodes after the SerpApi free trial (100 searches) runs out, rotated keys not updated in the component parameters, geo/gl parameters producing empty result pages, or a typo'd key configured per-node instead of globally.
Related errors
- GitHub search returned no items.
- Failed to create memory
- Failed to delete search
- Failed to update search
- Request failed
AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15).
Data as JSON: /api/errors/0f51253f8ac2ca1f.
Report an issue: GitHub.