{"record":{"id":"61c5844957d6e065","repo":"datawhalechina/hello-agents","slug":"error-61c584","errorCode":null,"errorMessage":"影片不存在或已下架","messagePattern":"影片不存在或已下架","errorType":"http","errorClass":"MovieServiceError","httpStatus":404,"severity":"warning","filePath":"Co-creation-projects/aatanxiao12-beep-YingQian/backend/app/services/movie_service.py","lineNumber":128,"sourceCode":"            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:\n            raise MovieServiceError(\"TMDB 返回非 JSON\") from e\n\n    def _poster_url(self, poster_path: Optional[str]) -> Optional[str]:\n        \"\"\"把 TMDB 相对 poster_path 拼成可访问的完整图片 URL。\"\"\"\n        if not poster_path:\n            return None\n        base = self.settings.tmdb_image_base_url.rstrip(\"/\")\n        return f\"{base}{poster_path}\"\n\n    def _parse_year(self, release_date: Optional[str]) -> Optional[int]:","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/aatanxiao12-beep-YingQian/backend/app/services/movie_service.py#L110-L146","documentation":"MovieServiceError with status_code=404 raised when TMDB returns HTTP 404 — the requested movie id does not exist (never assigned, or beyond the id space) or the content is unavailable in the requested language/region market and TMDB serves 404 instead of an empty body. Because get_detail builds /movie/{movie_id}?append_to_response=credits, a movie whose credits endpoint 404s also surfaces here.","triggerScenarios":"get_detail(movie_id) with an arbitrary/hallucinated id (LLM-generated ids are a classic source); id from a different TMDB region profile where the title is geo-blocked; very large ids beyond assigned range; a formerly valid id removed after a DMCA takedown; passing a TV show id to the /movie/ endpoint.","commonSituations":"Recommendation agent inventing plausible-looking ids; stale ids persisted from an old crawl; ids harvested from a third-party dataset that actually uses IMDb ids (tt...) rather than TMDB numeric ids.","solutions":["Resolve ids via search/discover first instead of trusting raw ids, then call get_detail on the returned result","Map external ids properly: use /find/{external_id}?external_source=imdb_id when starting from IMDb ids","If content was previously valid, re-search by title to locate the new/alternate TMDB entry","Catch this 404 upstream and fall back to a search-based flow rather than surfacing the error to the user"],"exampleFix":"# before\nmovie = service.get_detail(hallucinated_id)  # MovieServiceError 404\n\n# after\ntry:\n    movie = service.get_detail(movie_id)\nexcept MovieServiceError as e:\n    if e.status_code != 404:\n        raise\n    candidates = service.search(title_hint, year=year_hint)\n    if not candidates:\n        raise\n    movie = service.get_detail(candidates[0].id)","handlingStrategy":"fallback","validationCode":"def plausible_movie_id(mid) -> bool:\n    return isinstance(mid, int) and 0 < mid < 100_000_000","typeGuard":null,"tryCatchPattern":"try:\n    return service.get_detail(mid)\nexcept MovieServiceError as e:\n    if e.status_code != 404:\n        raise\n    hits = service.search(title_hint, year=year_hint)\n    return service.get_detail(hits[0].id) if hits else None","preventionTips":["Never trust ids from LLM output verbatim — resolve via search/find first","When starting from IMDb ids, use TMDB /find?external_source=imdb_id instead of guessing","Cache known-good ids so 404s trigger a one-time re-resolution, not per-request failures"],"tags":["tmdb","http-404","data-validation","llm-hallucination","python"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}