NanmiCoder/MediaCrawler · error · DataFetchError
{data.error.message}
Error message
{data.error.message} What it means
DataFetchError raised inside ZhiHuClient.request when the response parsed as JSON successfully but contains a top-level 'error' object. Zhihu reports API-level failures (invalid parameters, missing content, permission denied) this way with HTTP 200, so the client checks data['error'] after parsing and raises with the API's own error.message.
Source
Thrown at media_platform/zhihu/client.py:121
async with make_async_client(proxy=self.proxy) as client:
response = await client.request(method, url, timeout=self.timeout, **kwargs)
if response.status_code != 200:
utils.logger.error(f"[ZhiHuClient.request] Requset Url: {url}, Request error: {response.text}")
if response.status_code == 403:
raise ForbiddenError(response.text)
elif response.status_code == 404: # Content without comments also returns 404
return {}
raise DataFetchError(response.text)
if return_response:
return response.text
try:
data: Dict = response.json()
if data.get("error"):
utils.logger.error(f"[ZhiHuClient.request] Request error: {data}")
raise DataFetchError(data.get("error", {}).get("message"))
return data
except json.JSONDecodeError:
utils.logger.error(f"[ZhiHuClient.request] Request error: {response.text}")
raise DataFetchError(response.text)
async def get(self, uri: str, params=None, **kwargs) -> Union[Response, Dict, str]:
"""
GET request with header signing
Args:
uri: Request URI
params: Request parameters
Returns:
"""
final_uri = uri
if isinstance(params, dict):
final_uri += '?' + urlencode(params)View on GitHub (pinned to d6f7c5bb90)
Solutions
- Read the error.message embedded in the exception - it is zhihu's own description of the rejected request.
- Validate/sanitize content ids before requesting them.
- If the message hints at login requirements, refresh the cookie.
- Catch DataFetchError per item and skip the failing content.
Example fix
// before
comments = await zhihu_client.get(uri, params=params)
// after
try:
comments = await zhihu_client.get(uri, params=params)
except DataFetchError as e:
utils.logger.info(f"zhihu rejected {uri}: {e}")
comments = {} Defensive patterns
Strategy: try-catch
Validate before calling
def looks_like_zhihu_id(content_id: str) -> bool:
return bool(content_id) and len(content_id) >= 6 Try / catch
from media_platform.zhihu.exception import DataFetchError
try:
data = await zhihu_client.request("GET", url)
except DataFetchError as e:
if str(e).lower().startswith(("err", "missing", "invalid")):
utils.logger.info(f"zhihu rejected content: {e}")
return {}
raise Prevention
- Read the API's error.message embedded in the exception before guessing a cause.
- Filter content IDs that previously errored instead of re-requesting them each run.
- Watch for zhihu API error-envelope shape changes after site updates.
When it happens
Trigger: Requesting an answer/comment/content id that zhihu's API rejects (e.g. deleted content, wrong id format) or calling an endpoint without sufficient permission - HTTP is 200 but the body is an error envelope.
Common situations: Content ids harvested earlier that were later deleted; API contract changes adding new error cases; requesting logged-in-only content with an anonymous cookie.
Related errors
AI-assisted analysis of NanmiCoder/MediaCrawler@d6f7c5bb90 (2026-08-15).
Data as JSON: /api/errors/0697f8214edc1dc2.
Report an issue: GitHub.