D4Vinci/Scrapling · error · ValueError

At least one proxy must be provided

Error message

At least one proxy must be provided

What it means

Raised by `ProxyRotator.__init__` in scrapling/engines/toolbelt/proxy_rotation.py when the `proxies` list is empty. The rotator needs at least one proxy to cycle through, so an empty (or falsy) collection is rejected immediately rather than failing later during a request.

Source

Thrown at scrapling/engines/toolbelt/proxy_rotation.py:65

    """

    __slots__ = ("_proxies", "_proxy_to_index", "_strategy", "_current_index", "_lock")

    def __init__(
        self,
        proxies: List[ProxyType],
        strategy: RotationStrategy = cyclic_rotation,
    ):
        """
        Initialize the proxy rotator.

        :param proxies: List of proxy URLs or Playwright-style proxy dicts.
            - String format: "http://proxy1:8080" or "http://user:pass@proxy:8080"
            - Dict format: {"server": "http://proxy:8080", "username": "user", "password": "pass"}
        :param strategy: Rotation strategy function. Takes (proxies, current_index) and returns (proxy, next_index). Defaults to cyclic_rotation.
        """
        if not proxies:
            raise ValueError("At least one proxy must be provided")

        if not callable(strategy):
            raise TypeError(f"strategy must be callable, got {type(strategy).__name__}")

        self._strategy = strategy
        self._lock = Lock()

        # Validate and store proxies
        self._proxies: List[ProxyType] = []
        self._proxy_to_index: Dict[str, int] = {}  # O(1) lookup by unique key (server + username)
        for i, proxy in enumerate(proxies):
            if isinstance(proxy, (str, dict)):
                if isinstance(proxy, dict) and "server" not in proxy:
                    raise ValueError("Proxy dict must have a 'server' key")

                self._proxy_to_index[_get_proxy_key(proxy)] = i
                self._proxies.append(proxy)
            else:

View on GitHub (pinned to 5d213a2d47)

Solutions

  1. Supply at least one proxy string or dict: ProxyRotator(proxies=['http://p1:8080']).
  2. Check the pool is non-empty after loading: if not pool: use direct connection instead of constructing the rotator.
  3. Log the pool size where proxies are loaded so an empty source is visible before the rotator is built.

Example fix

# before
rotator = ProxyRotator(proxies=load_proxies())  # may be []

# after
pool = load_proxies()
if not pool:
    raise SystemExit('No proxies configured; aborting')
rotator = ProxyRotator(proxies=pool)
Defensive patterns

Strategy: validation

Validate before calling

pool = load_proxies()
if not pool:
    raise RuntimeError("proxy pool is empty; check proxy source before creating rotator")
rotator = ProxyRotator(proxies=pool)

Try / catch

try:
    rotator = ProxyRotator(proxies=pool)
except ValueError as e:
    if "At least one proxy" in str(e):
        rotator = None  # fall back to direct connection path
    else:
        raise

Prevention

When it happens

Trigger: Constructing ProxyRotator(proxies=[]) or ProxyRotator(proxies=[]) with a list produced by filtering, e.g. [p for p in pool if p] where everything was filtered out, or passing an empty default when no proxies were configured.

Common situations: Loading proxies from a file/env var that is empty on some machines; a proxy-fetching API returning zero results; CI environments without proxy credentials so the configured pool is empty.

Related errors


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