{"record":{"id":"9a281435f6794b80","repo":"crewAIInc/crewAI","slug":"invalid-url-e-s","errorCode":null,"errorMessage":"Invalid URL: {e!s}","messagePattern":"Invalid URL: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"lib/crewai-tools/src/crewai_tools/tools/selenium_scraping_tool/selenium_scraping_tool.py","lineNumber":43,"sourceCode":"\n    @field_validator(\"website_url\")\n    @classmethod\n    def validate_website_url(cls, v: str) -> str:\n        if not v:\n            raise ValueError(\"Website URL cannot be empty\")\n\n        if len(v) > 2048:  # Common maximum URL length\n            raise ValueError(\"URL is too long (max 2048 characters)\")\n\n        if not re.match(r\"^https?://\", v):\n            raise ValueError(\"URL must start with http:// or https://\")\n\n        try:\n            result = urlparse(v)\n            if not all([result.scheme, result.netloc]):\n                raise ValueError(\"Invalid URL format\")\n        except Exception as e:\n            raise ValueError(f\"Invalid URL: {e!s}\") from e\n\n        if re.search(r\"\\s\", v):\n            raise ValueError(\"URL cannot contain whitespace\")\n\n        return v\n\n\nclass SeleniumScrapingTool(BaseTool):\n    name: str = \"Read a website content\"\n    description: str = \"A tool that can be used to read a website content.\"\n    args_schema: type[BaseModel] = SeleniumScrapingToolSchema\n    website_url: str | None = None\n    driver: Any | None = None\n    cookie: dict[str, Any] | None = None\n    wait_time: int | None = 3\n    css_element: str | None = None\n    return_html: bool | None = False\n    _by: Any | None = None","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/crewAIInc/crewAI/blob/754d7323beb2fd042e33444a115ea2d5a47193f0/lib/crewai-tools/src/crewai_tools/tools/selenium_scraping_tool/selenium_scraping_tool.py#L25-L61","documentation":"Pydantic field_validator error from SeleniumScrapingToolSchema raised as the except branch of the urlparse try-block: it wraps any unexpected exception raised while parsing the URL (message interpolated as 'Invalid URL: {e}'). In practice the inner raises are ValueErrors re-wrapped here, so the message chains the original parsing failure detail. It indicates the URL string could not be structurally parsed at all.","triggerScenarios":"Passing values to website_url that make urlparse raise rather than return an incomplete result — e.g. certain non-string-like or severely malformed inputs; commonly seen as the wrapper around the 'Invalid URL format' branch when the inner ValueError propagates through the except.","commonSituations":"Dynamic URL assembly producing control characters or broken percent-encoding; values from untrusted user input that only look like URLs; debugging sessions where the raw exception text under 'Invalid URL:' reveals which parse step failed.","solutions":["Read the text after 'Invalid URL:' — it carries the underlying parse error identifying the malformed part.","Sanitize/percent-encode the URL before passing it (urllib.parse.quote for unsafe components).","Log the offending value on ValidationError to find which upstream producer emitted it."],"exampleFix":"# before\ntool = SeleniumScrapingTool(website_url=raw_user_input, css_element=\"article\")  # Invalid URL: ...\n\n# after\nfrom urllib.parse import urlparse\nparsed = urlparse(raw_user_input.strip())\nif not (parsed.scheme in (\"http\", \"https\") and parsed.netloc):\n    raise ValueError(f\"bad url from user: {raw_user_input!r}\")\ntool = SeleniumScrapingTool(website_url=parsed.geturl(), css_element=\"article\")","handlingStrategy":"validation","validationCode":"from urllib.parse import urlparse\n\ndef is_parseable_web_url(v: str) -> bool:\n    try:\n        p = urlparse(v)\n        return p.scheme in (\"http\", \"https\") and bool(p.netloc) and not any(ch.isspace() for ch in v)\n    except Exception:\n        return False","typeGuard":"def is_web_url(v) -> bool:\n    \"\"\"Narrow unknown input to a parseable http(s) URL without whitespace.\"\"\"\n    if not isinstance(v, str):\n        return False\n    try:\n        p = urlparse(v.strip())\n    except Exception:\n        return False\n    return p.scheme in (\"http\", \"https\") and bool(p.netloc) and not any(c.isspace() for c in v)","tryCatchPattern":"from pydantic import ValidationError\n\ntry:\n    tool = SeleniumScrapingTool(website_url=raw, css_element=css)\nexcept ValidationError as e:\n    log.error(\"rejected url %r: %s\", raw, e)  # msg carries the underlying parse reason\n    raise","preventionTips":["Sanitize URLs (strip, percent-encode unsafe chars) before passing them to the tool.","Log the raw rejected value so the faulty producer (form, file, LLM) is identifiable."],"tags":["validation","url","selenium","parsing","wrapper-exception"],"backgroundTag":null,"analyzedSha":"754d7323beb2fd042e33444a115ea2d5a47193f0","analyzedAt":"2026-08-15T04:06:56.746Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}