{"record":{"id":"4da14ca344d05e7e","repo":"datawhalechina/hello-agents","slug":"tmdb-e","errorCode":null,"errorMessage":"TMDB 请求超时: {e}","messagePattern":"TMDB 请求超时: (.+?)","errorType":"exception","errorClass":"MovieServiceError","httpStatus":null,"severity":"error","filePath":"Co-creation-projects/aatanxiao12-beep-YingQian/backend/app/services/movie_service.py","lineNumber":118,"sourceCode":"        if token:\n            headers[\"Authorization\"] = f\"Bearer {token}\"\n        else:\n            params[\"api_key\"] = api_key  # type: ignore[assignment]\n        return headers, params\n\n    def _get(self, path: str, extra_params: Optional[Dict[str, Any]] = None) -> dict:\n        \"\"\"对 TMDB 发 GET，统一处理超时、网络错误与非 2xx / 非 JSON。\"\"\"\n        headers, params = self._auth_headers_and_params()\n        if extra_params:\n            for k, v in extra_params.items():\n                if v is not None and v != \"\":\n                    params[k] = v\n\n        url = f\"{TMDB_API_BASE}{path}\"\n        try:\n            resp = self._client.get(url, headers=headers, params=params)\n        except httpx.TimeoutException as e:\n            raise MovieServiceError(f\"TMDB 请求超时: {e}\") from e\n        except httpx.HTTPError as e:\n            raise MovieServiceError(f\"TMDB 网络错误: {e}\") from e\n\n        if resp.status_code == 401:\n            raise MovieServiceError(\n                \"TMDB 鉴权失败：请检查 Access Token / API Key\",\n                status_code=401,\n            )\n        if resp.status_code == 404:\n            raise MovieServiceError(\"影片不存在或已下架\", status_code=404)\n        if resp.status_code >= 400:\n            raise MovieServiceError(\n                f\"TMDB 请求失败: HTTP {resp.status_code}, {resp.text[:200]}\"\n            )\n\n        try:\n            return resp.json()\n        except ValueError as e:","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/aatanxiao12-beep-YingQian/backend/app/services/movie_service.py#L100-L136","documentation":"MovieServiceError raised when the httpx client's GET to TMDB raises httpx.TimeoutException — the request exceeded the 30-second timeout configured on httpx.Client(timeout=30.0). Default status code is likely 503/500 class; it signals a slow upstream, not a code bug. Chained with `from e` so the specific timeout subtype (ConnectTimeout, ReadTimeout) is preserved.","triggerScenarios":"GET to api.themoviedb.org exceeding 30s during TMDB outages or rate-limit-induced throttling; client running in a network-restricted environment where connections stall (connect timeout to a blackholed IP); system under heavy load causing slow reads; DNS resolution hanging.","commonSituations":"Corporate proxy or firewall stalling outbound TLS; TMDB having a partial outage (check status.themoviedb.org); bursts of requests triggering server-side slowdown; GFW/network filtering in some regions causing connect hangs to TMDB.","solutions":["Retry with backoff (e.g. 2 attempts, exponential) for idempotent GETs — transient timeouts dominate","Tune the timeout: use httpx.Timeout(10.0, read=30.0) with a snappier connect timeout so dead connections fail fast","If in a filtered network region, route via a proxy (HTTP_PROXY/HTTPS_PROXY or a self-hosted mirror) that can reach TMDB","Check TMDB status page and your rate-limit headers before assuming code issues"],"exampleFix":"# before\nself._client = httpx.Client(timeout=30.0)\nexcept httpx.TimeoutException as e:\n    raise MovieServiceError(f\"TMDB 请求超时: {e}\") from e\n\n# after\nself._client = httpx.Client(\n    timeout=httpx.Timeout(10.0, read=30.0, write=10.0, pool=10.0)\n)\n# in _get, wrap with a small retry:\nfor attempt in range(3):\n    try:\n        resp = self._client.get(url, headers=headers, params=params)\n        break\n    except httpx.TimeoutException as e:\n        if attempt == 2:\n            raise MovieServiceError(f\"TMDB 请求超时（已重试3次）: {e}\", status_code=504) from e\n        time.sleep(2 ** attempt)","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"from app.services.movie_service import MovieServiceError\nimport time\n\nfor attempt in range(3):\n    try:\n        return service.get_detail(mid)\n    except MovieServiceError as e:\n        if '超时' not in str(e) or attempt == 2:\n            raise\n        time.sleep(2 ** attempt)","preventionTips":["Set explicit connect/read timeouts on httpx.Client so each phase fails predictably","Retry only idempotent GETs, with capped exponential backoff","Watch TMDB status page / rate-limit headers to distinguish upstream slowness from your own bursts"],"tags":["tmdb","httpx","timeout","network","retry","python"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}