{"record":{"id":"4d3b8bbe4ebf5044","repo":"datawhalechina/hello-agents","slug":"movie-id","errorCode":null,"errorMessage":"movie_id 必须为正整数","messagePattern":"movie_id 必须为正整数","errorType":"http","errorClass":"MovieServiceError","httpStatus":400,"severity":"warning","filePath":"Co-creation-projects/aatanxiao12-beep-YingQian/backend/app/services/movie_service.py","lineNumber":296,"sourceCode":"            genres=genre_names,\n            runtime=runtime,\n            rating=item.get(\"vote_average\"),\n            poster_url=self._poster_url(item.get(\"poster_path\")),\n            overview=item.get(\"overview\") or \"\",\n            tagline=(item.get(\"tagline\") or \"\").strip() or None,\n            original_title=original_title,\n            vote_count=vote_count,\n            original_language=(item.get(\"original_language\") or \"\").strip() or None,\n            countries=countries,\n            directors=directors,\n            cast=cast_names,\n            tmdb_url=f\"https://www.themoviedb.org/movie/{movie_id}\",\n        )\n\n    def get_detail(self, movie_id: int) -> MovieDetail:\n        \"\"\"按 id 取电影详情（含 credits：导演 / 主演）。\"\"\"\n        if movie_id <= 0:\n            raise MovieServiceError(\"movie_id 必须为正整数\", status_code=400)\n\n        data = self._get(\n            f\"/movie/{movie_id}\",\n            {\"append_to_response\": \"credits\"},\n        )\n        return self._map_detail(data)\n\n    def search(\n        self,\n        q: str,\n        year: Optional[int] = None,\n        page: int = 1,\n    ) -> List[CandidateMovie]:\n        \"\"\"按关键词搜索电影（TMDB GET /search/movie）。\"\"\"\n        query = (q or \"\").strip()\n        if not query:\n            raise MovieServiceError(\"搜索关键词 q 不能为空\", status_code=400)\n","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/aatanxiao12-beep-YingQian/backend/app/services/movie_service.py#L278-L314","documentation":"MovieServiceError with status_code=400 raised by get_detail when movie_id <= 0. This is an input-validation guard that fires before any network call: TMDB numeric ids are positive integers, so zero or negative values are caller bugs (often from unparsed user input or an LLM emitting a sentinel like 0 or -1).","triggerScenarios":"get_detail(0), get_detail(-1); movie_id parsed from free text where int() fell back to a default 0; None coerced to 0; id arithmetic underflow; frontend sending an empty form field that serializes to 0.","commonSituations":"LLM tool-calling emitting an invalid id; form default value of 0 slipping through; unit tests passing 0 as a dummy; ids read from a CSV with empty cells converted via int(cell or 0).","solutions":["Validate at the API boundary (FastAPI path/query param with gt=0) so bad input never reaches the service","Trace where the non-positive id originated and fix the default/parsing there","In agent pipelines, re-search for the title when an LLM emits an invalid id instead of forwarding it"],"exampleFix":"# before\n@app.get(\"/movies/{movie_id}\")\nasync def get_movie(movie_id: int):\n    return service.get_detail(movie_id)  # service raises 400\n\n# after\nfrom fastapi import Path\n\n@app.get(\"/movies/{movie_id}\")\nasync def get_movie(\n    movie_id: int = Path(..., gt=0),\n):\n    return service.get_detail(movie_id)  # FastAPI rejects <=0 with 422","handlingStrategy":"validation","validationCode":"def valid_movie_id(mid) -> bool:\n    return isinstance(mid, int) and not isinstance(mid, bool) and mid > 0","typeGuard":"from typing import Any\n\ndef is_positive_int(v: Any) -> bool:\n    return isinstance(v, int) and not isinstance(v, bool) and v > 0","tryCatchPattern":null,"preventionTips":["Declare FastAPI params with gt=0 (or pydantic Field(gt=0)) so the framework rejects bad ids with 422","Never default ids to 0 — use None and require the caller to supply a real id","Validate LLM tool outputs (movie ids) against is_positive_int before use"],"tags":["tmdb","validation","http-400","fastapi","python"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}