{"record":{"id":"bdb36bfedffb2ed5","repo":"datawhalechina/hello-agents","slug":"semantic-scholar-api-http-e-code-e-reason","errorCode":null,"errorMessage":"Semantic Scholar API 返回 HTTP {e.code}: {e.reason}","messagePattern":"Semantic Scholar API 返回 HTTP (.+?): (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"Co-creation-projects/chengH425-PaperAssistant/src/literature_tool.py","lineNumber":216,"sourceCode":"\n                with urllib.request.urlopen(req, timeout=20) as resp:\n                    return json.loads(resp.read().decode(\"utf-8\"))\n\n            except urllib.error.HTTPError as e:\n                if e.code == 429:\n                    # 速率限制：等待后重试\n                    wait = 2 ** (attempt + 1)  # 2s, 4s, 8s\n                    if attempt < max_retries - 1:\n                        time.sleep(wait)\n                        continue\n                    raise RuntimeError(\n                        \"API 请求频率已达上限（429 Too Many Requests）。\\n\"\n                        \"Semantic Scholar 免费额度为 100 次/5 分钟。\\n\"\n                        \"请稍等 1-5 分钟后重试，或申请免费 API Key：\\n\"\n                        \"https://www.semanticscholar.org/product/api\\n\"\n                        \"获取后在 .env 中设置 SEMANTIC_SCHOLAR_API_KEY\"\n                    ) from e\n                raise RuntimeError(\n                    f\"Semantic Scholar API 返回 HTTP {e.code}: {e.reason}\"\n                ) from e\n            except urllib.error.URLError as e:\n                last_error = e\n                if attempt < max_retries - 1:\n                    time.sleep(2 ** (attempt + 1))\n                    continue\n                raise RuntimeError(f\"网络连接失败: {str(e.reason)}\") from e\n\n        raise RuntimeError(f\"请求失败（已重试 {max_retries} 次）: {last_error}\")\n\n    def run(self, parameters: Dict[str, Any]) -> ToolResponse:\n        keyword = parameters.get(\"keyword\", \"\")\n        author = parameters.get(\"author\", \"\")\n        field = parameters.get(\"field\", \"\")\n\n        if not keyword and not author:\n            return ToolResponse.error(","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/chengH425-PaperAssistant/src/literature_tool.py#L198-L234","documentation":"RuntimeError raised when the Semantic Scholar API returns any non-429 HTTPError (e.g. 400 bad query, 401/403 invalid API key, 404 unknown endpoint, 5xx outage). The message interpolates the status code and reason: 'Semantic Scholar API returned HTTP {e.code}: {e.reason}'. Unlike 429, these errors are not retried — they propagate immediately.","triggerScenarios":"Passing a malformed or empty query parameter that the Graph API rejects with 400; setting `SEMANTIC_SCHOLAR_API_KEY` to an invalid/revoked value (401/403); hitting a temporary 5xx during API maintenance; using an outdated endpoint URL after an API version change.","commonSituations":"Typo'd or expired API key in .env, query strings containing unsupported operators or over-long inputs, Semantic Scholar infrastructure incidents.","solutions":["Match the status: 400 → fix the request parameters; 401/403 → fix/regenerate the API key in .env; 5xx → retry later or check status.semanticscholar.org.","Log the full request URL and query to see exactly what was sent when the 400 occurred.","If 401/403 with a key set, confirm the key header name/value are correct (x-api-key) and not quoted in .env.","Consider retrying 5xx responses with backoff the same way 429 is handled."],"exampleFix":"// before\nraise RuntimeError(\n    f\"Semantic Scholar API returned HTTP {e.code}: {e.reason}\"\n) from e\n\n# after\nif 500 <= e.code < 600 and attempt < max_retries - 1:\n    time.sleep(2 ** (attempt + 1))\n    continue\nraise RuntimeError(\n    f\"Semantic Scholar API returned HTTP {e.code}: {e.reason}\"\n) from e","handlingStrategy":"try-catch","validationCode":"import os\n\ndef api_key_valid_format() -> bool:\n    key = os.getenv(\"SEMANTIC_SCHOLAR_API_KEY\", \"\")\n    return key == \"\" or (key.isalnum() and len(key) >= 20)  # heuristic; empty = anonymous tier","typeGuard":null,"tryCatchPattern":"import re\n\ntry:\n    data = _request(url)\nexcept RuntimeError as e:\n    m = re.search(r\"HTTP (\\d+)\", str(e))\n    code = int(m.group(1)) if m else 0\n    if code == 400:\n        fix_query_params()          # non-retryable: bad request\n    elif 500 <= code < 600:\n        time.sleep(30); retry()     # server-side, retryable later\n    elif code in (401, 403):\n        raise ConfigError(\"SEMANTIC_SCHOLAR_API_KEY invalid\")\n    else:\n        raise","preventionTips":["URL-encode query parameters and validate them before sending.","Keep the API key current; test it with a single curl call after rotation.","Log request URL + status code on failure so 400s are diagnosable."],"tags":["http-error","semantic-scholar","api","network","python"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}