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()


    @staticmethod

View on GitHub (pinned to 7e80152142)

Solutions

  1. Pass a dict: virtual_scroll_config={"container": "#results", "scroll_count": 10}
  2. Or an instance: VirtualScrollConfig(container="#results")
  3. 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

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


AI-assisted analysis of unclecode/crawl4ai@7e80152142 (2026-08-14). Data as JSON: /api/errors/a3d81cf589cb87a0. Report an issue: GitHub.