D4Vinci/Scrapling · error · ValueError
CDP URL must use 'ws://', 'wss://', 'http://', or 'https://'
Error message
CDP URL must use 'ws://', 'wss://', 'http://', or 'https://' scheme
What it means
Raised when the `cdp_url` config value does not start with ws://, wss://, http://, or https://. Scrapling validates this up front because Playwright's connect_over_cdp requires a proper endpoint URL, and the check catches inputs like 'localhost:9222' or 'chromium:9222' before a confusing Playwright failure.
Source
Thrown at scrapling/engines/_browsers/_validators.py:112
dns_over_https: bool = False
def __post_init__(self): # pragma: no cover
"""Custom validation after msgspec validation"""
if self.page_action and not callable(self.page_action):
raise TypeError(f"page_action must be callable, got {type(self.page_action).__name__}")
if self.page_setup and not callable(self.page_setup):
raise TypeError(f"page_setup must be callable, got {type(self.page_setup).__name__}")
if self.proxy and self.proxy_rotator:
raise ValueError(
"Cannot use 'proxy_rotator' together with 'proxy'. "
"Use either a static proxy or proxy rotation, not both."
)
if self.proxy:
self.proxy = construct_proxy_dict(self.proxy)
if self.cdp_url:
cdp_msg = _is_invalid_cdp_url(self.cdp_url)
if cdp_msg:
raise ValueError(cdp_msg)
if not self.cookies:
self.cookies = []
if not self.extra_flags:
self.extra_flags = []
if not self.selector_config:
self.selector_config = {}
if not self.additional_args:
self.additional_args = {}
if not self.capture_xhr:
self.capture_xhr = None
if self.init_script is not None:
validation_msg = _is_invalid_file_path(self.init_script)
if validation_msg:
raise ValueError(validation_msg)
if self.executable_path is not None:View on GitHub (pinned to 5d213a2d47)
Solutions
- Prefix the endpoint with a supported scheme, e.g. cdp_url='http://localhost:9222'
- For WebSocket endpoints use the full ws://host:port/devtools/browser/<uuid> URL from http://host:port/json/version
- Do not pass a bare host:port
Example fix
// before session = StealthySession(cdp_url='localhost:9222') // after session = StealthySession(cdp_url='http://localhost:9222')
Defensive patterns
Strategy: validation
Validate before calling
ALLOWED = ('ws://', 'wss://', 'http://', 'https://')
assert cdp_url.startswith(ALLOWED), f'cdp_url must start with one of {ALLOWED}' Type guard
def is_valid_cdp_url(u: str) -> bool:
return isinstance(u, str) and u.startswith(('ws://', 'wss://', 'http://', 'https://')) Try / catch
try:
session = StealthySession(cdp_url=ep)
except ValueError as e:
if 'CDP URL' in str(e):
ep = 'http://' + ep # normalize host:port input
session = StealthySession(cdp_url=ep)
else:
raise Prevention
- Normalize user-supplied host:port to http://host:port before passing
- Fetch the real ws endpoint from http://host:port/json/version when connecting to Chrome
- Never pass a bare host:port as cdp_url
When it happens
Trigger: Passing cdp_url='localhost:9222' (no scheme), cdp_url='9222', or a pathlike endpoint without protocol. Note the ws endpoint usually looks like ws://host:port/devtools/browser/<id>.
Common situations: Copy-pasting the host:port from Chrome's --remote-debugging-port output without prefixing http://, or using the DevTools page URL instead of the WebSocket endpoint.
Related errors
- Invalid hostname for the CDP URL
- page_action must be callable, got {type(self.page_action).__
- page_setup must be callable, got {type(self.page_setup).__na
- Cannot use 'proxy_rotator' together with 'proxy'. Use either
- Init script path not found: {value}
AI-assisted analysis of D4Vinci/Scrapling@5d213a2d47 (2026-08-14).
Data as JSON: /api/errors/b52000f7df938c9a.
Report an issue: GitHub.