D4Vinci/Scrapling · error · TypeError
page_setup must be callable, got {type(self.page_setup).__na
Error message
page_setup must be callable, got {type(self.page_setup).__name__} What it means
Same __post_init__ validation as page_action but for `page_setup`: the value must be callable because it is invoked as a callback on the page (page_setup(page)) before navigation. A truthy non-callable (string, dict, result of a call) raises TypeError at config construction.
Source
Thrown at scrapling/engines/_browsers/_validators.py:101
locale: str | None = None
real_chrome: bool = False
cdp_url: Optional[str] = None
useragent: Optional[str] = None
extra_flags: Optional[List[str]] = None
blocked_domains: Optional[Set[str]] = None
block_ads: bool = False
retries: RetriesCount = 3
retry_delay: Seconds = 1
capture_xhr: str | None = None
executable_path: Optional[str] = None
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 = {}View on GitHub (pinned to 5d213a2d47)
Solutions
- Pass the reference: page_setup=my_setup (no parentheses)
- Resolve string names from config to real functions before creating the session/fetch params
- For async sessions use an async def callback
Example fix
// before session.fetch(url, page_setup=setup_page()) # calls now, passes result // after session.fetch(url, page_setup=setup_page)
Defensive patterns
Strategy: type-guard
Validate before calling
if page_setup is not None and not callable(page_setup):
raise TypeError('page_setup must be callable')
session.fetch(url, page_setup=page_setup) Type guard
def is_valid_page_setup(fn) -> bool:
return fn is None or callable(fn) Try / catch
try:
session.fetch(url, page_setup=cb)
except TypeError as e:
if 'page_setup must be callable' in str(e):
cb = resolve_callback(cb); session.fetch(url, page_setup=cb)
else:
raise Prevention
- Pass the function reference (page_setup=setup), not setup()
- Resolve serialized callback names before session creation
- Use async callbacks with async sessions
When it happens
Trigger: Passing page_setup as a string name, passing page_setup=setup_page() (calling instead of referencing), or passing a non-function object from dynamic config.
Common situations: Config-driven scraper setups where callbacks are serialized, or accidentally adding parentheses when passing the function.
Related errors
- page_action must be callable, got {type(self.page_action).__
- Invalid argument type: {e}
- Cannot use 'proxy_rotator' together with 'proxy'. Use either
- CDP URL must use 'ws://', 'wss://', 'http://', or 'https://'
- Init script path not found: {value}
AI-assisted analysis of D4Vinci/Scrapling@5d213a2d47 (2026-08-14).
Data as JSON: /api/errors/c899a54850974fe0.
Report an issue: GitHub.