{"record":{"id":"235fce905de25bc6","repo":"NanmiCoder/MediaCrawler","slug":"params-or-payload-is-required","errorCode":null,"errorMessage":"params or payload is required","messagePattern":"params or payload is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"media_platform/xhs/client.py","lineNumber":108,"sourceCode":"    async def _pre_headers(self, url: str, params: Optional[Dict] = None, payload: Optional[Dict] = None) -> Dict:\n        \"\"\"请求头参数签名 (使用 xhshow 纯算法)\n\n        Args:\n            url: 请求 URI path\n            params: GET 请求参数\n            payload: POST 请求参数\n\n        Returns:\n            Dict: 签名后的请求头参数\n        \"\"\"\n        if params is not None:\n            data = params\n            method = \"GET\"\n        elif payload is not None:\n            data = payload\n            method = \"POST\"\n        else:\n            raise ValueError(\"params or payload is required\")\n\n        # 使用 xhshow 纯算法生成签名\n        signs = sign_with_xhshow(\n            uri=url,\n            data=data,\n            cookie_str=self.headers.get(\"Cookie\", \"\"),\n            method=method,\n        )\n\n        headers = {\n            \"X-S\": signs[\"x-s\"],\n            \"X-T\": signs[\"x-t\"],\n            \"x-S-Common\": signs[\"x-s-common\"],\n            \"X-B3-Traceid\": signs[\"x-b3-traceid\"],\n        }\n        self.headers.update(headers)\n        return self.headers\n","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/NanmiCoder/MediaCrawler/blob/d6f7c5bb906b6dac40ddf343ef9e26438a3de092/media_platform/xhs/client.py#L90-L126","documentation":"Raised by XiaoHongShuClient's request-signing helper (_pre_headers) when neither query params nor a POST payload was supplied. Signing with the xhshow algorithm requires the exact data that will be sent, so the method refuses to sign an empty request. It is a ValueError indicating a programming error in the caller.","triggerScenarios":"Calling a GET API method with params=None, or a POST method with payload=None, e.g. get_note_info_with_zero_param on an empty keyword or a search call built from empty user input.","commonSituations":"A new endpoint wrapper added without forwarding its params argument; empty search keyword from config; refactor that dropped the payload argument.","solutions":["Find the xhs client method that made the call and make sure its params/payload argument is actually passed through to _pre_headers.","Validate upstream inputs (e.g. KEYWORDS) are non-empty before starting an xhs crawl.","Pass an empty dict explicitly only if the endpoint truly takes no parameters - otherwise supply the real query."],"exampleFix":"# before\nasync def get_note_comments(note_id: str):\n    return await self.get(\"/api/sns/web/v2/comment/page\", params=None)\n# after\nasync def get_note_comments(note_id: str, cursor=\"\"):\n    params = {\"note_id\": note_id, \"cursor\": cursor}\n    return await self.get(\"/api/sns/web/v2/comment/page\", params=params)","handlingStrategy":"validation","validationCode":"def has_request_data(params, payload) -> bool:\n    return params is not None or payload is not None","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Every API wrapper in xhs client must forward its params/payload to the signing helper.","Assert search keywords and IDs are non-empty before building requests.","Add a unit test per endpoint wrapper that fails if params is None."],"tags":["xhs","signing","validation","programming-error"],"backgroundTag":null,"analyzedSha":"d6f7c5bb906b6dac40ddf343ef9e26438a3de092","analyzedAt":"2026-08-15T01:39:07.505Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}