unclecode/crawl4ai · error · ValueError
virtual_scroll_config must be VirtualScrollConfig object or
Error message
virtual_scroll_config must be VirtualScrollConfig object or dict
What it means
CrawlerRunConfig accepts virtual_scroll_config as None, a VirtualScrollConfig instance, or a plain dict (converted via VirtualScrollConfig.from_dict). Any other type is rejected because the crawler needs typed fields (container selector, scroll step, etc.) to drive virtual-scroll page loading.
Source
Thrown at crawl4ai/async_configs.py:1891
self.link_preview_config = None
elif isinstance(link_preview_config, LinkPreviewConfig):
self.link_preview_config = link_preview_config
elif isinstance(link_preview_config, dict):
# Convert dict to config object for backward compatibility
self.link_preview_config = LinkPreviewConfig.from_dict(link_preview_config)
else:
raise ValueError("link_preview_config must be LinkPreviewConfig object or dict")
# Virtual Scroll Parameters
if virtual_scroll_config is None:
self.virtual_scroll_config = None
elif isinstance(virtual_scroll_config, VirtualScrollConfig):
self.virtual_scroll_config = virtual_scroll_config
elif isinstance(virtual_scroll_config, dict):
# Convert dict to config object for backward compatibility
self.virtual_scroll_config = VirtualScrollConfig.from_dict(virtual_scroll_config)
else:
raise ValueError("virtual_scroll_config must be VirtualScrollConfig object or dict")
# URL Matching Parameters
self.url_matcher = url_matcher
self.match_mode = match_mode
# Experimental Parameters
self.experimental = experimental or {}
# Anti-Bot Retry Parameters
self.max_retries = max_retries
self.fallback_fetch_function = fallback_fetch_function
# Compile C4A scripts if provided
if self.c4a_script and not self.js_code:
self._compile_c4a_script()
@staticmethodView on GitHub (pinned to 7e80152142)
Solutions
- Pass a dict: virtual_scroll_config={"container": "#results", "scroll_count": 10}
- Or an instance: VirtualScrollConfig(container="#results")
- Parse JSON strings before passing; verify the nested structure survived your config loader
Example fix
// before cfg = CrawlerRunConfig(virtual_scroll_config=["#results", 10]) // after cfg = CrawlerRunConfig(virtual_scroll_config=VirtualScrollConfig(container="#results", scroll_count=10))
Defensive patterns
Strategy: type-guard
Validate before calling
from crawl4ai.async_configs import VirtualScrollConfig
assert virtual_scroll_config is None or isinstance(virtual_scroll_config, (VirtualScrollConfig, dict)), \
"virtual_scroll_config must be VirtualScrollConfig or dict" Type guard
def is_virtual_scroll_config(v) -> bool:
return v is None or isinstance(v, (VirtualScrollConfig, dict)) Prevention
- Validate nested config shapes at the API boundary
- Construct VirtualScrollConfig explicitly in typed code
When it happens
Trigger: Passing virtual_scroll_config as a string, list, or an object of an unrelated class; passing a dict whose values then fail VirtualScrollConfig's own validation.
Common situations: Loading config from JSON where the nested object was flattened or stringified; version mismatches after VirtualScrollConfig was introduced or moved.
Related errors
- extraction_strategy must be an instance of ExtractionStrateg
- chunking_strategy must be an instance of ChunkingStrategy
- link_preview_config must be LinkPreviewConfig object or dict
- [NSTProxy] Invalid protocol: {protocol}
- concurrency must be positive
AI-assisted analysis of unclecode/crawl4ai@7e80152142 (2026-08-14).
Data as JSON: /api/errors/a3d81cf589cb87a0.
Report an issue: GitHub.