unclecode/crawl4ai · error · ValueError

Invalid hook type: {hook_type}

Error message

Invalid hook type: {hook_type}

What it means

A 500 raised by the stream-crawl setup path when a generic Exception (not config rejection, not a deliberate HTTPException) occurs while acquiring a crawler or starting `arun_many` — before the StreamingResponse begins. The crawler is released and the raw `str(e)` is returned as the detail, because once streaming starts this handler can no longer run.

Source

Thrown at crawl4ai/async_crawler_strategy.py:188

        - on_execution_started: Called when the execution starts.
        - before_goto: Called before a goto operation.
        - after_goto: Called after a goto operation.
        - before_return_html: Called before returning HTML content.
        - before_retrieve_html: Called before retrieving HTML content.

        All hooks except on_browser_created accepts a context and a page as arguments and **kwargs. However, on_browser_created accepts a browser and a context as arguments and **kwargs.

        Args:
            hook_type (str): The type of the hook.
            hook (Callable): The hook function to set.

        Returns:
            None
        """
        if hook_type in self.hooks:
            self.hooks[hook_type] = hook
        else:
            raise ValueError(f"Invalid hook type: {hook_type}")

    async def execute_hook(self, hook_type: str, *args, **kwargs):
        """
        Execute a hook function for a specific hook type.

        Args:
            hook_type (str): The type of the hook.
            *args: Variable length positional arguments.
            **kwargs: Keyword arguments.

        Returns:
            The return value of the hook function, if any.
        """
        hook = self.hooks.get(hook_type)
        if hook:
            if asyncio.iscoroutinefunction(hook):
                return await hook(*args, **kwargs)
            else:

View on GitHub (pinned to 7e80152142)

Solutions

  1. Read `detail` (raw exception message) and the server log line 'Stream crawl error:' with its traceback for the root cause
  2. If it is a browser/Playwright startup failure, verify the docker image and run the browser health check; restart the container if the pool is wedged
  3. Retry with backoff — transient browser launch races commonly self-heal
  4. Simplify the payload (no custom dispatcher/hooks) to isolate whether config-driven setup code is the trigger
Defensive patterns

Strategy: retry

Validate before calling

# preflight: confirm the service is healthy before streaming
async def preflight(client):
    r = await client.get("/health")
    r.raise_for_status()
    return True

Try / catch

for attempt in range(3):
    try:
        crawler, gen, hooks = await setup_stream(...)
        break
    except HTTPException as e:
        if e.status_code == 500 and attempt < 2:
            await asyncio.sleep(2 ** attempt)  # browser startup races often heal
            continue
        raise

Prevention

When it happens

Trigger: POSTing to the stream endpoint when browser acquisition fails (browser pool crash, Playwright launch error) or `crawler.arun_many(...)` throws during dispatcher setup. Note this covers setup only; errors during an already-started stream surface differently.

Common situations: Chromium missing or crashed in the container, browser pool exhausted/broken after an earlier OOM, dispatcher misconfiguration in the payload, or transient Playwright startup failures.

Related errors


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