{"record":{"id":"e627253f96614550","repo":"D4Vinci/Scrapling","slug":"cannot-use-proxy-rotator-together-with-proxy","errorCode":null,"errorMessage":"Cannot use 'proxy_rotator' together with 'proxy'. Use either a static proxy or proxy rotation, not both.","messagePattern":"Cannot use 'proxy_rotator' together with 'proxy'\\. Use either a static proxy or proxy rotation, not both\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"scrapling/engines/_browsers/_validators.py","lineNumber":103,"sourceCode":"    cdp_url: Optional[str] = None\n    useragent: Optional[str] = None\n    extra_flags: Optional[List[str]] = None\n    blocked_domains: Optional[Set[str]] = None\n    block_ads: bool = False\n    retries: RetriesCount = 3\n    retry_delay: Seconds = 1\n    capture_xhr: str | None = None\n    executable_path: Optional[str] = None\n    dns_over_https: bool = False\n\n    def __post_init__(self):  # pragma: no cover\n        \"\"\"Custom validation after msgspec validation\"\"\"\n        if self.page_action and not callable(self.page_action):\n            raise TypeError(f\"page_action must be callable, got {type(self.page_action).__name__}\")\n        if self.page_setup and not callable(self.page_setup):\n            raise TypeError(f\"page_setup must be callable, got {type(self.page_setup).__name__}\")\n        if self.proxy and self.proxy_rotator:\n            raise ValueError(\n                \"Cannot use 'proxy_rotator' together with 'proxy'. \"\n                \"Use either a static proxy or proxy rotation, not both.\"\n            )\n        if self.proxy:\n            self.proxy = construct_proxy_dict(self.proxy)\n        if self.cdp_url:\n            cdp_msg = _is_invalid_cdp_url(self.cdp_url)\n            if cdp_msg:\n                raise ValueError(cdp_msg)\n\n        if not self.cookies:\n            self.cookies = []\n        if not self.extra_flags:\n            self.extra_flags = []\n        if not self.selector_config:\n            self.selector_config = {}\n        if not self.additional_args:\n            self.additional_args = {}","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/D4Vinci/Scrapling/blob/5d213a2d4764002bfc4fed33c32fe09fa8b0bf7f/scrapling/engines/_browsers/_validators.py#L85-L121","documentation":"PlaywrightConfig.__post_init__ rejects configurations that set both `proxy` (a single static proxy) and `proxy_rotator` (an object yielding a proxy per request). The two mechanisms are mutually exclusive because the rotator would be silently ignored with a static proxy present.","triggerScenarios":"Creating StealthySession/PlaywrightSession (or a fetch call) with both proxy='http://...' and proxy_rotator=ProxyRotator(...) in the same config.","commonSituations":"Migrating from a static proxy to rotation and forgetting to remove the old proxy key; merging config dicts where both keys survive.","solutions":["Remove the `proxy` key when using proxy_rotator","Or drop proxy_rotator and keep the single static proxy","If you need a one-off static override per request, use fetch(url, proxy=...) which overrides the rotator per-call by design"],"exampleFix":"// before\nsession = StealthySession(proxy='http://u:p@host:8080', proxy_rotator=ProxyRotator([...]))\n\n// after\nsession = StealthySession(proxy_rotator=ProxyRotator([...]))\n# per-call static override:\nresp = session.fetch(url, proxy='http://u:p@host:8080')","handlingStrategy":"validation","validationCode":"if cfg.get('proxy') and cfg.get('proxy_rotator'):\n    del cfg['proxy']  # rotator wins; or drop the rotator instead\nsession = StealthySession(**cfg)","typeGuard":"def proxy_config_is_consistent(proxy, rotator) -> bool:\n    return not (proxy and rotator)","tryCatchPattern":"try:\n    session = StealthySession(proxy=p, proxy_rotator=r)\nexcept ValueError as e:\n    if 'proxy_rotator' in str(e):\n        session = StealthySession(proxy_rotator=r)\n    else:\n        raise","preventionTips":["Keep exactly one of proxy / proxy_rotator in any config source","Assert consistency when merging config dicts from multiple sources","Use fetch(url, proxy=...) for intentional per-call static overrides"],"tags":["validation","proxy","config","mutually-exclusive"],"backgroundTag":null,"analyzedSha":"5d213a2d4764002bfc4fed33c32fe09fa8b0bf7f","analyzedAt":"2026-08-14T22:23:09.440Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}