datawhalechina/hello-agents · error · MovieServiceError
TMDB 返回非 JSON
Error message
TMDB 返回非 JSON
What it means
MovieServiceError raised when resp.json() raises ValueError on a 2xx TMDB response — the body is not valid JSON. httpx raises json.JSONDecodeError (a ValueError subclass) here. Causes: an intermediary (captive portal, corporate proxy, CDN edge) returning HTML; response compressed/garbled; TMDB rarely returning an error page with 200.
Source
Thrown at Co-creation-projects/aatanxiao12-beep-YingQian/backend/app/services/movie_service.py:137
except httpx.HTTPError as e:
raise MovieServiceError(f"TMDB 网络错误: {e}") from e
if resp.status_code == 401:
raise MovieServiceError(
"TMDB 鉴权失败:请检查 Access Token / API Key",
status_code=401,
)
if resp.status_code == 404:
raise MovieServiceError("影片不存在或已下架", status_code=404)
if resp.status_code >= 400:
raise MovieServiceError(
f"TMDB 请求失败: HTTP {resp.status_code}, {resp.text[:200]}"
)
try:
return resp.json()
except ValueError as e:
raise MovieServiceError("TMDB 返回非 JSON") from e
def _poster_url(self, poster_path: Optional[str]) -> Optional[str]:
"""把 TMDB 相对 poster_path 拼成可访问的完整图片 URL。"""
if not poster_path:
return None
base = self.settings.tmdb_image_base_url.rstrip("/")
return f"{base}{poster_path}"
def _parse_year(self, release_date: Optional[str]) -> Optional[int]:
"""从 release_date(YYYY-MM-DD)解析上映年份。"""
if not release_date or len(release_date) < 4:
return None
try:
return int(release_date[:4])
except ValueError:
return None
def ensure_genres(self) -> None:View on GitHub (pinned to 606a07d341)
Solutions
- Log resp.headers.get('content-type') and a body snippet when this fires — HTML content-type immediately implicates an intermediary
- Whitelist api.themoviedb.org in the proxy/captive-portal environment or route through an authenticated proxy
- Treat as retryable once: one re-request often bypasses a one-off bad intermediate response
- Set headers={'Accept': 'application/json'} explicitly (already done) and verify no middleware strips it
Example fix
# before
try:
return resp.json()
except ValueError as e:
raise MovieServiceError("TMDB 返回非 JSON") from e
# after
try:
return resp.json()
except ValueError as e:
ct = resp.headers.get("content-type", "")
snippet = resp.text[:120].replace("\n", " ")
raise MovieServiceError(
f"TMDB 返回非 JSON (content-type={ct}, body~ {snippet})"
) from e Defensive patterns
Strategy: try-catch
Validate before calling
# verify the response smells like JSON before parsing
ct = resp.headers.get('content-type', '')
if 'json' not in ct:
raise MovieServiceError(f'TMDB 返回非 JSON (content-type={ct})') Try / catch
except MovieServiceError as e:
if '非 JSON' in str(e):
return retry_once() # captive portals/proxies usually poison one response
raise Prevention
- Check content-type includes application/json before resp.json() for a clearer error
- Whitelist API hosts through proxies; disable captive networks for servers
- Log a body snippet on decode failure to identify the intercepting middlebox
When it happens
Trigger: Captive-portal Wi-Fi injecting an HTML login page on the API request; a proxy or firewall replacing the response body; response truncated mid-body by a connection drop (httpx would usually raise ReadError instead, but short bodies can parse as invalid JSON); Accept header negotiation returning non-JSON error content.
Common situations: Container in a network that transparently redirects unauthenticated traffic; hotel/airport Wi-Fi; a misconfigured reverse proxy in front of the service rewriting responses; extremely rare TMDB edge malfunctions.
Related errors
- TMDB 请求超时: {e}
- TMDB 网络错误: {e}
- TMDB 未配置:请在 .env 设置 TMDB_ACCESS_TOKEN 或 TMDB_API_KEY
- TMDB 鉴权失败:请检查 Access Token / API Key
- 影片不存在或已下架
AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14).
Data as JSON: /api/errors/a88b173622d51516.
Report an issue: GitHub.