D4Vinci/Scrapling · error · ValueError

Invalid proxy string!

Error message

Invalid proxy string!

What it means

Raised by `construct_proxy_dict` in scrapling/engines/toolbelt/navigation.py when a proxy passed as a string cannot be parsed into a usable proxy URL. The string is run through `urlparse`, and if the scheme is not one of http/https/socks4/socks5, or the URL has no hostname, the library rejects it before Playwright ever sees it. This is a config-validation error: the proxy string is structurally invalid, not merely unreachable.

Source

Thrown at scrapling/engines/toolbelt/navigation.py:107

            else:
                await route.continue_()
        else:
            await route.continue_()

    return handler


def construct_proxy_dict(proxy_string: str | Dict[str, str] | Tuple) -> Dict:
    """Validate a proxy and return it in the acceptable format for Playwright
    Reference: https://playwright.dev/python/docs/network#http-proxy

    :param proxy_string: A string or a dictionary representation of the proxy.
    :return:
    """
    if isinstance(proxy_string, str):
        proxy = urlparse(proxy_string)
        if proxy.scheme not in ("http", "https", "socks4", "socks5") or not proxy.hostname:
            raise ValueError("Invalid proxy string!")

        try:
            result = {
                "server": f"{proxy.scheme}://{proxy.hostname}",
                "username": proxy.username or "",
                "password": proxy.password or "",
            }
            if proxy.port:
                result["server"] += f":{proxy.port}"
            return result
        except ValueError:
            # Urllib will say that one of the parameters above can't be casted to the correct type like `int` for port etc...
            raise ValueError("The proxy argument's string is in invalid format!")

    elif isinstance(proxy_string, dict):
        try:
            validated = convert(proxy_string, ProxyDict)
            result_dict = structs.asdict(validated)

View on GitHub (pinned to 5d213a2d47)

Solutions

  1. Prefix the proxy string with an explicit supported scheme, e.g. 'http://proxy1:8080' or 'socks5://proxy1:1080'.
  2. Ensure the string contains a hostname after the scheme (not just credentials or a port).
  3. If the proxy has auth, embed it as 'scheme://user:pass@host:port'.
  4. Alternatively pass a Playwright-style dict {'server': ..., 'username': ..., 'password': ...} which skips string parsing.

Example fix

// before
proxy = "proxy1:8080"
Fetcher.get(url, proxy=proxy)

// after
proxy = "http://proxy1:8080"
Fetcher.get(url, proxy=proxy)
Defensive patterns

Strategy: validation

Validate before calling

from urllib.parse import urlparse

def is_valid_proxy_string(p: str) -> bool:
    if not isinstance(p, str):
        return False
    u = urlparse(p)
    return u.scheme in ("http", "https", "socks4", "socks5") and bool(u.hostname)

proxy = "proxy1:8080"
assert is_valid_proxy_string(proxy), f"bad proxy: {proxy!r}"

Type guard

def is_proxy_string(value: object) -> bool:
    return isinstance(value, str) and is_valid_proxy_string(value)

Try / catch

try:
    fetcher.fetch(url, proxy=proxy)
except ValueError as e:
    if "Invalid proxy string" in str(e):
        raise ConfigError(f"proxy {proxy!r} needs scheme+host, e.g. http://host:port") from e
    raise

Prevention

When it happens

Trigger: Calling a fetcher (e.g. `Fetcher.get(..., proxy=...)`) or `construct_proxy_dict` directly with strings like `"proxy1:8080"` (no scheme), `"http://"` (no hostname), `"ftp://proxy:8080"` (unsupported scheme), or `"user:pass@proxy:8080"` (scheme missing, credentials alone).

Common situations: Proxy vendor sends host:port only; users copy proxy strings from dashboards that omit the scheme; using an ftp or other unsupported scheme; typos like `http//proxy:8080`.

Related errors


AI-assisted analysis of D4Vinci/Scrapling@5d213a2d47 (2026-08-14). Data as JSON: /api/errors/30ff0411e3d1d2c5. Report an issue: GitHub.