D4Vinci/Scrapling · error · ValueError

Cannot use 'proxy_rotator' together with 'proxy' or 'proxies

Error message

Cannot use 'proxy_rotator' together with 'proxy' or 'proxies'. Use either a static proxy or proxy rotation, not both.

What it means

Raised in _ConfigurationLogic.__init__ (the base of every static fetcher/session class) when the constructor receives both a proxy_rotator and a static proxy/proxies argument. Scrapling treats proxy rotation and static proxying as mutually exclusive strategies, so it fails fast at construction time instead of silently letting one override the other. This is a configuration contract error, not a network error.

Source

Thrown at scrapling/engines/static.py:92

        self._stealth = kwargs.get("stealthy_headers", True)
        self._default_proxies = kwargs.get("proxies") or {}
        self._default_proxy = kwargs.get("proxy") or None
        self._default_proxy_auth = kwargs.get("proxy_auth") or None
        self._default_timeout = kwargs.get("timeout", 30)
        self._default_headers = kwargs.get("headers") or {}
        self._default_retries = kwargs.get("retries", 3)
        self._default_retry_delay = kwargs.get("retry_delay", 1)
        self._default_follow_redirects = kwargs.get("follow_redirects", "safe")
        self._default_max_redirects = kwargs.get("max_redirects", 30)
        self._default_verify = kwargs.get("verify", True)
        self._default_cert = kwargs.get("cert") or None
        self._default_http3 = kwargs.get("http3", False)
        self.selector_config = kwargs.get("selector_config") or {}
        self._is_alive = False
        self._proxy_rotator: Optional[ProxyRotator] = kwargs.get("proxy_rotator")

        if self._proxy_rotator and (self._default_proxy or self._default_proxies):
            raise ValueError(
                "Cannot use 'proxy_rotator' together with 'proxy' or 'proxies'. "
                "Use either a static proxy or proxy rotation, not both."
            )

    @staticmethod
    def _get_param(kwargs: Dict, key: str, default: Any) -> Any:
        """Get parameter from kwargs if present, otherwise return default."""
        return kwargs[key] if key in kwargs else default

    def _merge_request_args(self, **method_kwargs) -> Dict[str, Any]:
        """Merge request-specific arguments with default session arguments."""
        url = method_kwargs.pop("url")

        # Get parameters from kwargs or use defaults
        impersonate = self._get_param(method_kwargs, "impersonate", self._default_impersonate)
        impersonate = _select_random_browser(impersonate)
        http3_enabled = self._get_param(method_kwargs, "http3", self._default_http3)
        stealth = self._get_param(method_kwargs, "stealth", self._stealth)

View on GitHub (pinned to 5d213a2d47)

Solutions

  1. Remove the 'proxy' (or 'proxies') kwarg and keep only proxy_rotator if you want rotating proxies.
  2. Or remove proxy_rotator and keep the static 'proxy'/'proxies' kwarg if you want a single fixed proxy.
  3. If you need a fallback static proxy, encode it as the last entry inside the ProxyRotator's proxy list instead of a separate kwarg.

Example fix

# before
session = FetcherSession(proxy='http://10.0.0.1:8080', proxy_rotator=ProxyRotator([...]))

# after
session = FetcherSession(proxy_rotator=ProxyRotator(['http://10.0.0.1:8080', 'http://10.0.0.2:8080']))
Defensive patterns

Strategy: validation

Validate before calling

from scrapling.engines.proxy import ProxyRotator

def make_static_fetcher(proxy=None, proxies=None, proxy_rotator=None):
    if proxy_rotator is not None and (proxy or proxies):
        raise ValueError('Choose one: static proxy OR proxy_rotator, not both')
    return FetcherSession(proxy=proxy, proxies=proxies, proxy_rotator=proxy_rotator)

Type guard

def has_exclusive_proxy_config(proxy, proxies, rotator) -> bool:
    return not (rotator is not None and (proxy is not None or proxies is not None))

Try / catch

try:
    session = FetcherSession(proxy=proxy, proxy_rotator=rotator)
except ValueError as e:
    if 'proxy_rotator' in str(e):
        # config conflict: drop the static proxy and rebuild
        session = FetcherSession(proxy_rotator=rotator)
    else:
        raise

Prevention

When it happens

Trigger: Calling FetcherSession(proxy='http://...', proxy_rotator=rotator), AsyncFetcherSession(proxies={...}, proxy_rotator=rotator), or any static fetcher class (Fetcher/AsyncFetcher) with both kwargs set. Also triggered when a FetcherSession forwards its saved config into an inner _SyncSessionLogic/_ASyncSessionLogic while both fields were somehow populated.

Common situations: Copy-pasting a proxy from an existing scraper while adding the new ProxyRotator feature; migrating from static proxies to rotation and forgetting to delete the old 'proxy' kwarg; passing a dict of proxies that was valid pre-rotator versions.

Related errors


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