{"record":{"id":"76231db784765f63","repo":"Panniantong/Agent-Reach","slug":"limit-must-be-non-negative","errorCode":null,"errorMessage":"limit must be non-negative","messagePattern":"limit must be non-negative","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent_reach/channels/xueqiu.py","lineNumber":239,"sourceCode":"                }\n            )\n        return results\n\n    def get_hot_posts(self, limit: int = 20) -> list:\n        \"\"\"获取雪球热门帖子。\n\n        Uses the v4 public timeline endpoint which returns posts in a `list`\n        array.  Each item carries a JSON-encoded `data` field containing the\n        actual post payload (title, description, user, like_count, target).\n\n        Args:\n            limit: 最多返回条数（上限 50）\n\n        Returns a list of dicts with keys:\n          id, title, text, author, likes, url\n        \"\"\"\n        if limit < 0:\n            raise ValueError(\"limit must be non-negative\")\n        limit = min(limit, 50)\n        if limit == 0:\n            return []\n        data = _get_json(\n            \"https://xueqiu.com/v4/statuses/public_timeline_by_category.json\"\n            f\"?since_id=-1&max_id=-1&count={limit}&category=-1\"\n        )\n        items = data.get(\"list\") or []\n        results = []\n        for item in items[:limit]:\n            # Each item.data is a JSON string containing the real post payload\n            try:\n                post = (\n                    json.loads(item[\"data\"])\n                    if isinstance(item.get(\"data\"), str)\n                    else {}\n                )\n            except (json.JSONDecodeError, KeyError):","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/Panniantong/Agent-Reach/blob/93ae1d18c37b707dec053c7c4f9d91cd8ef8943d/agent_reach/channels/xueqiu.py#L221-L257","documentation":"XueqiuChannel.search (or the public-timeline helper at agent_reach/channels/xueqiu.py:239) validates its limit argument up front: a negative limit raises ValueError('limit must be non-negative') before any network call. Values 1..50 are accepted (anything above 50 is clamped with min(limit, 50)); 0 short-circuits to an empty list.","triggerScenarios":"Calling the public timeline API with limit=-1 (e.g. code that computes limit as size - remaining and underflows, or treats -1 as 'default' like some APIs do). Note: the check is limit < 0, so limit=0 is valid and returns [].","commonSituations":"Porting code from APIs where -1 means 'server default' (xueqiu's own web API uses -1 sentinels for since_id/max_id); arithmetic that computes a negative count (10 - 20); passing an unvalidated CLI argument straight through.","solutions":["Pass a non-negative limit; use 0 for 'nothing' and let the channel clamp anything over 50","If -1 was meant as 'default', pass a concrete value like 20 instead","Fix the arithmetic producing the negative value (e.g. max(0, remaining))","Validate/validate user-supplied counts at your own CLI boundary with argparse type=int plus a min check"],"exampleFix":"# before\nresults = channel.search(query, limit=page_size - offset)  # can go negative\n\n# after\nresults = channel.search(query, limit=max(0, page_size - offset))","handlingStrategy":"validation","validationCode":"def safe_limit(requested: int) -> int:\n    \"\"\"Clamp to the xueqiu channel's accepted range before calling.\"\"\"\n    return max(0, min(requested, 50))\n\nresults = channel.search(query, limit=safe_limit(user_count))","typeGuard":"def is_valid_xueqiu_limit(value: object) -> bool:\n    return isinstance(value, int) and not isinstance(value, bool) and value >= 0","tryCatchPattern":"try:\n    results = channel.search(query, limit=n)\nexcept ValueError as exc:\n    if \"non-negative\" in str(exc):\n        results = channel.search(query, limit=abs(n))  # or reject input upstream\n    else:\n        raise","preventionTips":["Clamp user-supplied counts with max(0, min(n, 50)) at your own boundary","Remember 0 is valid (empty result) and >50 is silently clamped — do not rely on exact counts above 50","Never use -1 as a 'server default' sentinel here; pick a concrete page size"],"tags":["xueqiu","validation","argument-error","python"],"backgroundTag":null,"analyzedSha":"93ae1d18c37b707dec053c7c4f9d91cd8ef8943d","analyzedAt":"2026-08-14T22:54:06.735Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}