{"record":{"id":"74e33edc6b84c4a5","repo":"D4Vinci/Scrapling","slug":"at-least-one-proxy-must-be-provided","errorCode":null,"errorMessage":"At least one proxy must be provided","messagePattern":"At least one proxy must be provided","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"scrapling/engines/toolbelt/proxy_rotation.py","lineNumber":65,"sourceCode":"    \"\"\"\n\n    __slots__ = (\"_proxies\", \"_proxy_to_index\", \"_strategy\", \"_current_index\", \"_lock\")\n\n    def __init__(\n        self,\n        proxies: List[ProxyType],\n        strategy: RotationStrategy = cyclic_rotation,\n    ):\n        \"\"\"\n        Initialize the proxy rotator.\n\n        :param proxies: List of proxy URLs or Playwright-style proxy dicts.\n            - String format: \"http://proxy1:8080\" or \"http://user:pass@proxy:8080\"\n            - Dict format: {\"server\": \"http://proxy:8080\", \"username\": \"user\", \"password\": \"pass\"}\n        :param strategy: Rotation strategy function. Takes (proxies, current_index) and returns (proxy, next_index). Defaults to cyclic_rotation.\n        \"\"\"\n        if not proxies:\n            raise ValueError(\"At least one proxy must be provided\")\n\n        if not callable(strategy):\n            raise TypeError(f\"strategy must be callable, got {type(strategy).__name__}\")\n\n        self._strategy = strategy\n        self._lock = Lock()\n\n        # Validate and store proxies\n        self._proxies: List[ProxyType] = []\n        self._proxy_to_index: Dict[str, int] = {}  # O(1) lookup by unique key (server + username)\n        for i, proxy in enumerate(proxies):\n            if isinstance(proxy, (str, dict)):\n                if isinstance(proxy, dict) and \"server\" not in proxy:\n                    raise ValueError(\"Proxy dict must have a 'server' key\")\n\n                self._proxy_to_index[_get_proxy_key(proxy)] = i\n                self._proxies.append(proxy)\n            else:","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/D4Vinci/Scrapling/blob/5d213a2d4764002bfc4fed33c32fe09fa8b0bf7f/scrapling/engines/toolbelt/proxy_rotation.py#L47-L83","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Supply at least one proxy string or dict: ProxyRotator(proxies=['http://p1:8080']).","Check the pool is non-empty after loading: if not pool: use direct connection instead of constructing the rotator.","Log the pool size where proxies are loaded so an empty source is visible before the rotator is built."],"exampleFix":"# before\nrotator = ProxyRotator(proxies=load_proxies())  # may be []\n\n# after\npool = load_proxies()\nif not pool:\n    raise SystemExit('No proxies configured; aborting')\nrotator = ProxyRotator(proxies=pool)","handlingStrategy":"validation","validationCode":"pool = load_proxies()\nif not pool:\n    raise RuntimeError(\"proxy pool is empty; check proxy source before creating rotator\")\nrotator = ProxyRotator(proxies=pool)","typeGuard":null,"tryCatchPattern":"try:\n    rotator = ProxyRotator(proxies=pool)\nexcept ValueError as e:\n    if \"At least one proxy\" in str(e):\n        rotator = None  # fall back to direct connection path\n    else:\n        raise","preventionTips":["Assert a non-empty pool right where proxies are loaded.","Log pool size at startup so empty sources are obvious.","Decide the no-proxy behavior (abort vs direct) before constructing the rotator."],"tags":["proxy","proxy-rotation","validation"],"backgroundTag":null,"analyzedSha":"5d213a2d4764002bfc4fed33c32fe09fa8b0bf7f","analyzedAt":"2026-08-14T22:23:09.440Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}