{"record":{"id":"0009d52b8a84a6de","repo":"infiniflow/ragflow","slug":"querit-urls-must-be-absolute-http-or-https-urls","errorCode":null,"errorMessage":"Querit urls must be absolute HTTP or HTTPS URLs.","messagePattern":"Querit urls must be absolute HTTP or HTTPS URLs\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/tools/querit.py","lineNumber":378,"sourceCode":"        \"format\": format,\n        \"crawlTimeout\": crawl_timeout,\n        \"extrasMeta\": extras_meta,\n    }\n\n\ndef _normalize_contents_urls(urls: Any) -> Any:\n    if isinstance(urls, str):\n        return [url.strip() for url in urls.split(\",\") if url.strip()]\n    return urls\n\n\ndef _validate_contents_inputs(urls: Any, format: Any, crawl_timeout: Any, extras_meta: Any) -> None:\n    if not isinstance(urls, list) or not 1 <= len(urls) <= 10 or any(not isinstance(url, str) or not url.strip() for url in urls):\n        raise ValueError(\"Querit urls must contain between 1 and 10 non-empty strings.\")\n    for url in urls:\n        parsed = urlparse(url)\n        if parsed.scheme not in {\"http\", \"https\"} or not parsed.netloc:\n            raise ValueError(\"Querit urls must be absolute HTTP or HTTPS URLs.\")\n    if format not in QUERIT_CONTENT_FORMATS:\n        raise ValueError(\"Querit format must be text, markdown, or html.\")\n    if type(crawl_timeout) is not int or not 1 <= crawl_timeout <= 60:\n        raise ValueError(\"Querit crawl_timeout must be an integer from 1 to 60.\")\n    if type(extras_meta) is not bool:\n        raise ValueError(\"Querit extras_meta must be a boolean.\")\n\n\ndef _validate_contents_response(response_data: Any) -> None:\n    if not isinstance(response_data, dict):\n        raise TypeError(\"Querit API response must be a JSON object.\")\n    if \"results\" in response_data and not isinstance(response_data[\"results\"], list):\n        raise TypeError(\"Querit API response field results must be an array.\")\n    if \"statuses\" in response_data and not isinstance(response_data[\"statuses\"], list):\n        raise TypeError(\"Querit API response field statuses must be an array.\")\n\n\ndef _validate_search_inputs(","sourceCodeStart":360,"sourceCodeEnd":396,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/agent/tools/querit.py#L360-L396","documentation":"ValueError from _validate_contents_inputs(): every entry in the urls list must parse as an absolute HTTP(S) URL — scheme exactly 'http' or 'https' AND a non-empty netloc. Scheme-relative ('//host/path'), bare hostnames ('example.com/page'), and other schemes (ftp://, file://) are rejected.","triggerScenarios":"urls containing 'example.com/page' (no scheme), '//cdn.example.com/x' (protocol-relative), 'ftp://files.example.com/x', or a value like 'https://' with empty netloc.","commonSituations":"Users pasting URLs copied from browsers that strip the scheme; LLM tool-call outputs emitting bare domains; data pipelines carrying internal ftp/file URIs; trailing whitespace is fine (stripped earlier) but missing scheme is not.","solutions":["Prefix each URL with http:// or https:// (prefer https).","Normalize before the call: if '://' not in url, prepend 'https://'.","Remove ftp://, file://, mailto: entries — only http(s) is supported.","Validate with urllib.parse.urlparse in your caller so bad rows are dropped or fixed before invoking the tool."],"exampleFix":"# before\nurls = [\"example.com/page\", \"ftp://x.com/f\"]\n\n# after\nfrom urllib.parse import urlparse\nraw = [\"example.com/page\", \"https://ok.com\"]\nurls = [u if urlparse(u).scheme in {\"http\", \"https\"} else \"https://\" + u for u in raw if not u.startswith(\"ftp://\")]","handlingStrategy":"validation","validationCode":"from urllib.parse import urlparse\ndef absolute_http_urls(urls: list[str]) -> bool:\n    return all(urlparse(u).scheme in {\"http\", \"https\"} and urlparse(u).netloc for u in urls)","typeGuard":"def is_absolute_http_url(u: Any) -> bool:\n    if not isinstance(u, str):\n        return False\n    p = urlparse(u)\n    return p.scheme in {\"http\", \"https\"} and bool(p.netloc)","tryCatchPattern":"try:\n    querit_contents._invoke(urls=urls)\nexcept ValueError as e:\n    if \"absolute HTTP\" in str(e):\n        urls = [\"https://\" + u if not urlparse(u).scheme else u for u in urls]\n        querit_contents._invoke(urls=urls)\n    raise","preventionTips":["Normalize scheme-less inputs by prefixing https:// at the boundary.","Reject ftp/file/mailto schemes in ingestion pipelines before they reach Querit.","Prefer copying full URLs (with scheme) from browser address bars."],"tags":["validation","urls","querit","input"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}