Fixing Proxy URL had no scheme
The proxy is written without http:// in front. urllib3 refuses it; newer requests and pip guess instead, which turns the same mistake into vaguer errors.
In short
Write the proxy as a full URL: http://USER:PASS@host:port. Check HTTPS_PROXY, HTTP_PROXY and ALL_PROXY too: a variable set to host:port causes the same error in code that never mentions a proxy.
The message comes from urllib3, the HTTP library under requests, pip, Selenium and many others. Given a proxy like via.proxies.vision:9000, it won’t assume http://:
urllib3.exceptions.ProxySchemeUnknown: Proxy URL had no scheme, should start with http:// or https://Nothing was sent. We passed the same schemeless proxy to each library:
| Where | What you see |
|---|---|
urllib3.ProxyManager(…) | ProxySchemeUnknown: Proxy URL had no scheme, should start with http:// or https:// |
Selenium webdriver.Remote() with HTTPS_PROXY=host:port | ProxySchemeUnknown: Proxy URL had no scheme, should start with http:// or https:// |
| requests 2.25 | InvalidURL: Proxy URL had no scheme, should start with http:// or https:// |
| requests 2.34 | adds http:// itself (see below) |
| httpx 0.28 | ValueError: Unknown scheme for proxy URL URL('via.proxies.vision:9000') |
host:port:user:pass in requests | InvalidURL: Failed to parse: '…' is not a valid host or port |
The variable nobody looked at
Selenium is the common surprise. Its remote connection reads HTTPS_PROXY on its own, so a variable left as host:port by a shell profile or a CI setting breaks webdriver.Remote() even though your script sets no proxy. With http:// in the variable, the same script got past it. If the grid is inside your network, add its host to NO_PROXY so it isn’t reached through the proxy.
host:port:user:pass is a list format
Proxy lists and many tools use host:port:user:pass. Libraries don’t: they want a URL. Rearrange it to http://user:pass@host:port.
Newer requests adds http:// to a proxy without a scheme instead of raising. That works for host:port. With a login it depends on the username, because name:password@host:port already looks like a scheme followed by a colon:
The first line fails with Please check proxy URL. It is malformed and could be missing the host., a message that points nowhere near the cause. Code that worked with one account can break with the next. Always write the scheme.
pip sends its downloads through the same libraries, but it doesn’t show the proxy error. A proxy that refuses the connection turns into a missing package:
ERROR: Could not find a version that satisfies the requirement six (from versions: none)
ERROR: No matching distribution found for six-v isn’t enough; with -vvv the cause appears, here a proxy given without a login: Could not fetch URL https://pypi.org/simple/six/: proxy connection error: ('Unable to connect to proxy', OSError('Tunnel connection failed: 407 Proxy Authentication Required')). A username of letters only (--proxy alice:secret@host:port) fails like requests above. The fix is the same: --proxy http://USER:PASS@host:port, or the scheme in HTTPS_PROXY. pip and SOCKS proxies.
A setup that works
Ran unchanged on Python 3.13 with requests 2.34 and pip 26.2.
import os
from urllib.parse import quote
import requests
user = quote(os.environ["PROXY_USER"] + "-country-de", safe="")
password = quote(os.environ["PROXY_PASS"], safe="")
# Always write the scheme. Without it, a username like "alice" is read as the scheme,
# and urllib3, Selenium and older requests refuse the URL outright.
proxy = f"http://{user}:{password}@via.proxies.vision:9000"
r = requests.get("https://ipinfo.io/json", proxies={"http": proxy, "https": proxy}, timeout=30)
print(r.status_code, r.text)export HTTPS_PROXY="http://$PROXY_USER-country-de:$PROXY_PASS@via.proxies.vision:9000"
export HTTP_PROXY="$HTTPS_PROXY"
pip download --no-deps -d /tmp/pkgs sixSpecial characters
quote(…, safe="") encodes characters like @ or : in the login, which would otherwise end the username early. In a shell variable, percent-encode them by hand (@ becomes %40).
http://, even for https:// sites
The scheme describes how you talk to the proxy, not the website. Our port 9000 speaks plain HTTP and opens an encrypted tunnel to the site; https:// there fails differently. What that looks like.
What does 'Proxy URL had no scheme, should start with http:// or https://' mean?
Why do I get it from Selenium?
Why doesn't requests show this error any more?
pip says 'No matching distribution found'. Can that be the proxy?
What does httpx say instead?
Keep reading
aiohttp Proxy Errors: ClientHttpProxyError 407, SOCKS5 and trust_env
aiohttp's ClientHttpProxyError explained, why its message leaks your proxy password, socks5:// without aiohttp-socks, and rotation.
6 min read · #python#errors
httpx: unexpected keyword argument 'proxies' — Fix Without Downgrading
httpx 0.28 removed proxies=. What replaces it (proxy= and mounts=), the OpenAI SDK case, SOCKS5 and environment proxies.
5 min read · #python#errors
Scrapy: Could not open CONNECT tunnel with proxy (407, 403, SOCKS5)
What the status in Scrapy's TunnelError means, why socks5:// only times out, and a proxy middleware that works. Every case reproduced.
7 min read · #scrapy#python
Residential proxies, pay per GB
HTTP and SOCKS5. Country, city and sticky sessions in the username. No subscription.