crewAIInc/crewAI · error · ValueError

formats can only contain 'markdown' or 'html'

Error message

formats can only contain 'markdown' or 'html'

What it means

ValueError raised by HyperbrowserLoadTool._prepare_params when the 'formats' list inside scrape_options contains anything other than 'markdown' or 'html'. The tool validates the LLM/caller-supplied params dict before converting it into typed ScrapeOptions, whitelisting exactly two format strings.

Source

Thrown at lib/crewai-tools/src/crewai_tools/tools/hyperbrowser_load_tool/hyperbrowser_load_tool.py:88

    def _prepare_params(params: dict[str, Any]) -> dict[str, Any]:
        """Prepare session and scrape options parameters."""
        try:
            from hyperbrowser.models.scrape import (  # type: ignore[import-untyped]
                ScrapeOptions,
            )
            from hyperbrowser.models.session import (  # type: ignore[import-untyped]
                CreateSessionParams,
            )
        except ImportError as e:
            raise ImportError(
                "`hyperbrowser` package not found, please run `pip install hyperbrowser`"
            ) from e

        if "scrape_options" in params:
            if "formats" in params["scrape_options"]:
                formats = params["scrape_options"]["formats"]
                if not all(fmt in ["markdown", "html"] for fmt in formats):
                    raise ValueError("formats can only contain 'markdown' or 'html'")

        if "session_options" in params:
            params["session_options"] = CreateSessionParams(**params["session_options"])
        if "scrape_options" in params:
            params["scrape_options"] = ScrapeOptions(**params["scrape_options"])
        return params

    def _extract_content(self, data: Any | None) -> str:
        """Extract content from response data."""
        content = ""
        if data:
            content = data.markdown or data.html or ""
        return content

    def _run(
        self,
        url: str,
        operation: Literal["scrape", "crawl"] = "scrape",

View on GitHub (pinned to 754d7323be)

Solutions

  1. Use only 'markdown' and/or 'html' in scrape_options.formats.
  2. Strip unsupported entries before invoking: fmts = [f for f in fmts if f in ('markdown','html')].
  3. Get content type from the response via the tool's own extraction (data.markdown / data.html) instead of requesting extra formats.

Example fix

# before
params = {'scrape_options': {'formats': ['rawHtml', 'markdown']}}

# after
params = {'scrape_options': {'formats': ['html', 'markdown']}}
Defensive patterns

Strategy: validation

Validate before calling

ALLOWED_FORMATS = {'markdown', 'html'}
so = params.setdefault('scrape_options', {})
fmts = so.get('formats', ['markdown'])
so['formats'] = [f for f in fmts if f in ALLOWED_FORMATS]
if not so['formats']:
    so['formats'] = ['markdown']

Type guard

def formats_valid(formats: list[str]) -> bool:
    return all(f in ('markdown', 'html') for f in formats)

Try / catch

try:
    tool.run(url, params=params)
except ValueError as e:
    if 'formats' in str(e):
        params['scrape_options']['formats'] = ['markdown']
        tool.run(url, params=params)
    else:
        raise

Prevention

When it happens

Trigger: Passing scrape_options={'formats': ['markdown', 'screenshot']} or ['rawHtml'], ['json'], or even ['Markdown'] (case-sensitive whitelist) in the params handed to the tool's run method.

Common situations: Copy-pasting scrape_options from Firecrawl docs (which support rawHtml, screenshot, links) into the Hyperbrowser tool; LLM agents inventing formats; case mismatches.

Related errors


AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15). Data as JSON: /api/errors/7a9ab0e5ac582845. Report an issue: GitHub.