unclecode/crawl4ai · error · ValueError

At least one of include_internal or include_external must be

Error message

At least one of include_internal or include_external must be True

What it means

LinkPreviewConfig requires at least one of include_internal / include_external to be True. With both False there is no link set to preview, so the config would describe work that can never produce results — the constructor rejects it.

Source

Thrown at crawl4ai/async_configs.py:1207

        self.exclude_patterns = exclude_patterns
        self.concurrency = concurrency
        self.timeout = timeout
        self.max_links = max_links
        self.query = query
        self.score_threshold = score_threshold
        self.verbose = verbose
        
        # Validation
        if concurrency <= 0:
            raise ValueError("concurrency must be positive")
        if timeout <= 0:
            raise ValueError("timeout must be positive")
        if max_links <= 0:
            raise ValueError("max_links must be positive")
        if score_threshold is not None and not (0.0 <= score_threshold <= 1.0):
            raise ValueError("score_threshold must be between 0.0 and 1.0")
        if not include_internal and not include_external:
            raise ValueError("At least one of include_internal or include_external must be True")
    
    @staticmethod
    def from_dict(config_dict: Dict[str, Any]) -> "LinkPreviewConfig":
        """Create LinkPreviewConfig from dictionary (for backward compatibility)."""
        if not config_dict:
            return None
        
        return LinkPreviewConfig(
            include_internal=config_dict.get("include_internal", True),
            include_external=config_dict.get("include_external", False),
            include_patterns=config_dict.get("include_patterns"),
            exclude_patterns=config_dict.get("exclude_patterns"),
            concurrency=config_dict.get("concurrency", 10),
            timeout=config_dict.get("timeout", 5),
            max_links=config_dict.get("max_links", 100),
            query=config_dict.get("query"),
            score_threshold=config_dict.get("score_threshold"),
            verbose=config_dict.get("verbose", False)

View on GitHub (pinned to 7e80152142)

Solutions

  1. Enable at least one category, e.g. LinkPreviewConfig(include_external=True)
  2. When mapping user config, default one flag to True: include_internal=cfg.get('include_internal', True)
  3. Skip constructing the config (pass None) when the user intends no previews at all

Example fix

// before
cfg = LinkPreviewConfig(include_internal=False, include_external=False)
// after
cfg = LinkPreviewConfig(include_internal=False, include_external=True)
Defensive patterns

Strategy: validation

Validate before calling

include_internal = user_cfg.get("include_internal", True)
include_external = user_cfg.get("include_external", False)
if not include_internal and not include_external:
    include_external = True  # or refuse with a clear message
cfg = LinkPreviewConfig(include_internal=include_internal, include_external=include_external)

Prevention

When it happens

Trigger: LinkPreviewConfig(include_internal=False, include_external=False), typically when both flags come from config keys that default to False or are toggled off in pairs.

Common situations: Building the config from a dict where the user set internal=false intending external-only but also left external=false; feature-flag matrices that turn both off.

Related errors


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