{"record":{"id":"9845e74fddf9894c","repo":"sansan0/TrendRadar","slug":"invalid-parameter-9845e7","errorCode":"INVALID_PARAMETER","errorMessage":"无效的 URL: {url}","messagePattern":"无效的 URL: (.+?)","errorType":"error_code","errorClass":"InvalidParameterError","httpStatus":null,"severity":"error","filePath":"mcp_server/tools/article_reader.py","lineNumber":75,"sourceCode":"\n    def read_article(\n        self,\n        url: str,\n        timeout: int = DEFAULT_TIMEOUT\n    ) -> Dict:\n        \"\"\"\n        读取单篇文章内容（Markdown 格式）\n\n        Args:\n            url: 文章链接\n            timeout: 请求超时时间（秒），默认 30\n\n        Returns:\n            文章内容字典\n        \"\"\"\n        try:\n            if not url or not url.startswith((\"http://\", \"https://\")):\n                raise InvalidParameterError(\n                    f\"无效的 URL: {url}\",\n                    suggestion=\"URL 必须以 http:// 或 https:// 开头\"\n                )\n\n            self._throttle()\n\n            response = requests.get(\n                f\"{JINA_READER_BASE}/{url}\",\n                headers=self._build_headers(),\n                timeout=timeout\n            )\n\n            if response.status_code == 200:\n                return {\n                    \"success\": True,\n                    \"data\": {\n                        \"url\": url,\n                        \"content\": response.text,","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/sansan0/TrendRadar/blob/8ee26026ba6c11dec41a95fb3895a7162876caa1/mcp_server/tools/article_reader.py#L57-L93","documentation":"InvalidParameterError from read_article in article_reader.py: the URL must be a non-empty string starting with http:// or https:// before any network call is made (the Jina Reader proxy prefix is prepended afterward). This is a pure input-format check, raised before the throttle and the HTTP request. Code INVALID_PARAMETER.","triggerScenarios":"Passing None, an empty string, 'ftp://…', 'www.example.com' (no scheme), or a relative path; URLs extracted from markdown where the scheme got stripped; whitespace-prefixed URLs still fail if they don't start with the scheme.","commonSituations":"Feeding crawler output fields that contain bare domains; LLM tool callers passing the article title instead of a URL; copy-paste losing the scheme; data source returning mobileUrl without protocol.","solutions":["Ensure the URL starts with http:// or https:// (add https:// to bare domains).","Strip whitespace and validate format before calling.","Check that you passed the URL field, not the title field, of a news item."],"exampleFix":"# before\nreader.read_article(url=\"www.example.com/post\")\n# after\nurl = url.strip()\nif not url.startswith((\"http://\", \"https://\")):\n    url = \"https://\" + url\nreader.read_article(url=url)","handlingStrategy":"validation","validationCode":"def normalize_url(u: str) -> str | None:\n    if not isinstance(u, str):\n        return None\n    u = u.strip()\n    if not u.startswith((\"http://\", \"https://\")):\n        u = \"https://\" + u\n    return u if u.startswith((\"http://\", \"https://\")) else None\n\nurl = normalize_url(url)\nif url is None:\n    raise ValueError(\"not a usable URL\")","typeGuard":"def is_http_url(v) -> TypeGuard[str]:\n    return isinstance(v, str) and v.startswith((\"http://\", \"https://\"))","tryCatchPattern":null,"preventionTips":["Strip and scheme-check every URL at the boundary where crawler data enters your system.","Reject/repair bare-domain URLs before passing them to the reader tool."],"tags":["validation","url","article-reader","mcp"],"backgroundTag":null,"analyzedSha":"8ee26026ba6c11dec41a95fb3895a7162876caa1","analyzedAt":"2026-08-15T01:42:18.084Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}