psf/requests · error · InvalidURL

{e.args}

Error message

{e.args}

What it means

Raised by PreparedRequest.prepare_url when the underlying url_parse raises LocationParseError (from urllib3's src/urllib3/util/url.py). The message is reconstructed from the original error's args so the caller sees the precise parse failure (e.g. which character broke parsing). This wraps a low-level parse exception in requests' own InvalidURL for a consistent exception hierarchy.

Source

Thrown at src/requests/models.py:513

            url = url.decode("utf8")
        else:
            url = str(url)

        # Remove leading whitespaces from url
        url = url.lstrip()

        # Don't do any URL preparation for non-HTTP schemes like `mailto`,
        # `data` etc to work around exceptions from `url_parse`, which
        # handles RFC 3986 only.
        if ":" in url and not url.lower().startswith("http"):
            self.url = url
            return

        # Support for unicode domain names and paths.
        try:
            scheme, auth, host, port, path, query, fragment = parse_url(url)
        except LocationParseError as e:
            raise InvalidURL(*e.args)

        if not scheme:
            raise MissingSchema(
                f"Invalid URL {url!r}: No scheme supplied. "
                f"Perhaps you meant https://{url}?"
            )

        if not host:
            raise InvalidURL(f"Invalid URL {url!r}: No host supplied")

        # In general, we want to try IDNA encoding the hostname if the string contains
        # non-ASCII characters. This allows users to automatically get the correct IDNA
        # behaviour. For strings containing only ASCII characters, we need to also verify
        # it doesn't start with a wildcard (*), before allowing the unencoded hostname.
        if not unicode_is_ascii(host):
            try:
                host = self._get_idna_encoded_host(host)
            except UnicodeError:

View on GitHub (pinned to 8068356288)

Solutions

  1. Validate or sanitize the URL before passing it to requests (use urllib.parse.urlparse and check .scheme/.netloc are non-empty).
  2. Strip whitespace and control characters from URL components: url.strip().
  3. URL-encode path/query segments with urllib.parse.quote before assembly.

Example fix

// before
requests.get(user_input)

// after
from urllib.parse import urlparse
p = urlparse(user_input.strip())
if not p.scheme or not p.netloc:
    raise ValueError(f'bad url: {user_input!r}')
requests.get(p.geturl())
Defensive patterns

Strategy: validation

Validate before calling

from urllib.parse import urlparse

def is_parseable_url(url: str) -> bool:
    try:
        p = urlparse(url)
        return bool(p.scheme) and bool(p.netloc)
    except ValueError:
        return False

Type guard

from urllib.parse import urlparse

def is_well_formed_url(url: str) -> bool:
    if not isinstance(url, str) or not url.strip():
        return False
    p = urlparse(url.strip())
    return bool(p.scheme in ('http', 'https')) and bool(p.netloc)

Try / catch

from requests.exceptions import InvalidURL

try:
    resp = requests.get(url)
except InvalidURL as e:
    # log and reject the input
    raise

Prevention

When it happens

Trigger: Passing a malformed URL to requests.get/Session.request — e.g. unbalanced brackets in IPv6 ('http://[::1'), stray characters, spaces, or control characters; URLs with invalid percent-encoding; URLs constructed by string concatenation that produced garbage.

Common situations: Building URLs from untrusted/user input without validation; copy-paste artifacts (trailing spaces, smart quotes); templating bugs that emit 'http:///host' (triple slash) or missing protocol separators.

Related errors


AI-assisted analysis of psf/requests@8068356288 (2026-08-11). Data as JSON: /api/errors/3109338761042325. Report an issue: GitHub.