psf/requests · error · MissingSchema

Invalid URL {url!r}: No scheme supplied. Perhaps you meant h

Error message

Invalid URL {url!r}: No scheme supplied. Perhaps you meant https://{url}?

What it means

A `MissingSchema` exception raised by `PreparedRequest.prepare_url` when `urllib3.util.parse_url` finds no scheme component in the URL. Requests needs the scheme to pick a connection adapter (http:// vs https://), so a bare host like 'example.com/path' cannot be dispatched. The message suggests the likely fix of prepending https://.

Source

Thrown at src/requests/models.py:516

        # 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:
                raise InvalidURL("URL has an invalid label.")
        elif host.startswith(("*", ".")):
            raise InvalidURL("URL has an invalid label.")

View on GitHub ↗ (pinned to 414f0513c3)

Solutions

  1. Prepend an explicit scheme: `requests.get('https://' + url)` (as the error message suggests).
  2. Normalize inputs at the boundary: `if '://' not in url: url = 'https://' + url` before making requests.
  3. If using a base URL from config, validate it at startup (e.g. with `urllib.parse.urlparse(url).scheme`) and fail fast with a clear config error.

Example fix

# before
requests.get('api.example.com/v1/users')

# after
requests.get('https://api.example.com/v1/users')
Defensive patterns

Strategy: validation

Validate before calling

from urllib.parse import urlparse
parsed = urlparse(url)
if not parsed.scheme:
    url = "https://" + url

Try / catch

from requests.exceptions import MissingSchema
try:
    resp = requests.get(url)
except MissingSchema:
    resp = requests.get("https://" + url)

Prevention

When it happens

Trigger: `requests.get('example.com')`, `requests.get('//example.com/x')`, or a URL built by joining strings where the scheme part ended up empty. Note URLs containing ':' that don't start with 'http' (e.g. mailto:) bypass this check entirely at src/requests/models.py:505.

Common situations: URLs read from config files, environment variables, CSVs, or user input where people naturally omit the scheme; base-URL concatenation bugs (`base + path` where base is empty or lost its prefix); copy-pasting a domain from a browser bar that hides the scheme.

Related errors


AI-assisted analysis of psf/requests@414f0513c3 (2026-07-31). Data as JSON: /data/errors/11675c841b2d515d.json. Report an issue: GitHub ↗.