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
- Enable at least one category, e.g. LinkPreviewConfig(include_external=True)
- When mapping user config, default one flag to True: include_internal=cfg.get('include_internal', True)
- 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
- Default one flag to True in config loaders
- Reject all-off combinations at the API boundary with a helpful message
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
- concurrency must be positive
- timeout must be positive
- max_links must be positive
- score_threshold must be between 0.0 and 1.0
- link_preview_config must be LinkPreviewConfig object or dict
AI-assisted analysis of unclecode/crawl4ai@7e80152142 (2026-08-14).
Data as JSON: /api/errors/ec4abf046684e5b3.
Report an issue: GitHub.