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

  1. Read the error.message embedded in the exception - it is zhihu's own description of the rejected request.
  2. Validate/sanitize content ids before requesting them.
  3. If the message hints at login requirements, refresh the cookie.
  4. 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

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.