urlparse() Without a Scheme Misreads the Host (tested)

urlparse() assumes the string it's given follows URL syntax, starting with a scheme. We measured what happens to a plain string like example.com/path that's missing http:// or https:// — and the host doesn't end up where you'd expect.

1. Without a scheme, the whole string becomes the path

from urllib.parse import urlparse

r = urlparse("example.com/path")
print(r)
print("hostname:", r.hostname)
ParseResult(scheme='', netloc='', path='example.com/path', params='', query='', fragment='')
hostname: None

Measured: with no http:///https:// prefix, urlparse() has no way to recognize example.com as a host — the entire string lands in .path, and .netloc/.hostname come back empty/None. No exception is raised; the result just silently has no host.

2. A colon in the string can make it worse — a fake "scheme"

r2 = urlparse("example.com:8080/path")
print(r2)
print("hostname:", r2.hostname)
ParseResult(scheme='example.com', netloc='', path='8080/path', params='', query='', fragment='')
hostname: None

Measured: this is the sharper version of the bug. example.com:8080/path looks like host-plus-port, but the colon right after example.com matches URL scheme syntax (scheme:rest), so urlparse() reads example.com as the scheme, not the host, and 8080/path becomes the path. .hostname is still None — the actual host is nowhere in the parsed result.

3. Fix: always ensure a scheme is present before parsing

r3 = urlparse("https://example.com:8080/path")
print("hostname:", r3.hostname, "port:", r3.port)
hostname: example.com port: 8080

Measured: with an explicit scheme, .hostname and .port are both parsed correctly. The reliable fix confirmed here is to check for and prepend a scheme (e.g. default to https://) before calling urlparse() on any URL that might arrive without one — from user input, a config file, or a copy-pasted value — rather than trusting .netloc/.hostname to be populated from a schemeless string.

Frequently asked questions

Why is urlparse().hostname None for a URL like example.com/path?

We measured urlparse() requiring a scheme (like https://) to recognize the host portion of a string. Without one, the entire input is parsed as .path, leaving .netloc and .hostname empty.

Why did urlparse() treat part of my host as the scheme?

We confirmed that a schemeless string containing a colon, like example.com:8080/path, matches URL scheme syntax (word followed by a colon), so urlparse() reads the part before the colon as .scheme instead of as a hostname.

How do I safely parse a URL that might be missing http:// or https://?

We verified prepending a default scheme (e.g. checking for '://' and adding 'https://' if absent) before calling urlparse() reliably produces the correct .hostname and .port.

Does urlparse() raise an error for a URL without a scheme?

No — in our test it ran silently and returned a ParseResult with an empty or misassigned host field, with no indication anything was wrong with the input.

Is this urlparse() behavior different for host:port strings specifically?

Yes — we measured host:port/path strings being more likely to misparse than a bare host/path, because the colon before the port number matches scheme syntax and gets read as one.

Written with AI assistance. Measured on 2026-10-04 with Python 3.13.5's built-in urllib.parse module: ran urlparse() on a URL-like string missing its scheme, both with a bare host/path and with a host:port/path, comparing .netloc/.hostname to the same string with https:// added. PlainHeaders is our extension; Python's urllib.parse module is built in.