{"record":{"id":"7cff73130f5a63cd","repo":"FoundationAgents/MetaGPT","slug":"got-error-from-serpapi-res-error-7cff73","errorCode":null,"errorMessage":"Got error from SerpAPI: {res['error']}","messagePattern":"Got error from SerpAPI: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"metagpt/tools/search_engine_serper.py","lineNumber":91,"sourceCode":"            }\n            payloads.append({**self.payload, **_payload})\n        return json.dumps(payloads, sort_keys=True)\n\n    def get_headers(self) -> Dict[str, str]:\n        headers = {\"X-API-KEY\": self.api_key, \"Content-Type\": \"application/json\"}\n        return headers\n\n    @staticmethod\n    def _process_response(res: dict, as_string: bool = False) -> str:\n        \"\"\"Process response from SerpAPI.\"\"\"\n        # logger.debug(res)\n        focus = [\"title\", \"snippet\", \"link\"]\n\n        def get_focused(x):\n            return {i: j for i, j in x.items() if i in focus}\n\n        if \"error\" in res.keys():\n            raise ValueError(f\"Got error from SerpAPI: {res['error']}\")\n        if \"answer_box\" in res.keys() and \"answer\" in res[\"answer_box\"].keys():\n            toret = res[\"answer_box\"][\"answer\"]\n        elif \"answer_box\" in res.keys() and \"snippet\" in res[\"answer_box\"].keys():\n            toret = res[\"answer_box\"][\"snippet\"]\n        elif \"answer_box\" in res.keys() and \"snippet_highlighted_words\" in res[\"answer_box\"].keys():\n            toret = res[\"answer_box\"][\"snippet_highlighted_words\"][0]\n        elif \"sports_results\" in res.keys() and \"game_spotlight\" in res[\"sports_results\"].keys():\n            toret = res[\"sports_results\"][\"game_spotlight\"]\n        elif \"knowledge_graph\" in res.keys() and \"description\" in res[\"knowledge_graph\"].keys():\n            toret = res[\"knowledge_graph\"][\"description\"]\n        elif \"snippet\" in res[\"organic\"][0].keys():\n            toret = res[\"organic\"][0][\"snippet\"]\n        else:\n            toret = \"No good search result found\"\n\n        toret_l = []\n        if \"answer_box\" in res.keys() and \"snippet\" in res[\"answer_box\"].keys():\n            toret_l += [get_focused(res[\"answer_box\"])]","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/FoundationAgents/MetaGPT/blob/11cdf466d042aece04fc6cfd13b28e1a70341b1f/metagpt/tools/search_engine_serper.py#L73-L109","documentation":"ValueError from SerperWrapper._process_response: the Serper.dev response JSON contains an 'error' key. Unlike the SerpAPI variant, this wrapper has no tolerated no-results case — any error field raises immediately. Note the message text says 'SerpAPI' even though this is the serper.dev client; that is a copy-paste artifact in the source and does not change the meaning.","triggerScenarios":"Invalid/expired serper.dev key; exhausted credits (free tier gives ~2500 queries); malformed request payload — anything that makes serper.dev return {'error': ...}.","commonSituations":"Long batch runs burning through the free tier; stale key after rotation; error message confusingly mentioning 'SerpAPI' leading developers to debug the wrong provider.","solutions":["Read the error string inside the message to identify the real cause (key vs credits)","For credit exhaustion, upgrade or wait for quota reset; for keys, update SERPER_API_KEY","Wrap in try/except ValueError with retry/backoff for transient upstream errors"],"exampleFix":"# before\nres = await serper.run(query)\n# after\ntry:\n    res = await serper.run(query)\nexcept ValueError as e:\n    # message says 'SerpAPI' but provider is serper.dev; inspect the inner error text\n    log.warning(\"serper.dev error: %s\", e)\n    raise","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    res = await serper.run(query)\nexcept ValueError as e:\n    msg = str(e)\n    if \"Invalid API key\" in msg or \"credit\" in msg.lower():\n        raise  # permanent: fix credentials/plan\n    await asyncio.sleep(5)\n    res = await serper.run(query)  # transient: retry once","preventionTips":["Remember the 'SerpAPI' text in this serper.dev error is a library typo — debug the serper account","Watch free-tier credit burn in long-running agent loops","Distinguish permanent vs transient errors before retrying"],"tags":["search","serper","api-error","credentials","quota"],"backgroundTag":null,"analyzedSha":"11cdf466d042aece04fc6cfd13b28e1a70341b1f","analyzedAt":"2026-08-14T23:20:02.994Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}