{"record":{"id":"25b91bfbb05dd740","repo":"unclecode/crawl4ai","slug":"invalid-hook-type-hook-type","errorCode":null,"errorMessage":"Invalid hook type: {hook_type}","messagePattern":"Invalid hook type: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"crawl4ai/async_crawler_strategy.py","lineNumber":188,"sourceCode":"        - on_execution_started: Called when the execution starts.\n        - before_goto: Called before a goto operation.\n        - after_goto: Called after a goto operation.\n        - before_return_html: Called before returning HTML content.\n        - before_retrieve_html: Called before retrieving HTML content.\n\n        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.\n\n        Args:\n            hook_type (str): The type of the hook.\n            hook (Callable): The hook function to set.\n\n        Returns:\n            None\n        \"\"\"\n        if hook_type in self.hooks:\n            self.hooks[hook_type] = hook\n        else:\n            raise ValueError(f\"Invalid hook type: {hook_type}\")\n\n    async def execute_hook(self, hook_type: str, *args, **kwargs):\n        \"\"\"\n        Execute a hook function for a specific hook type.\n\n        Args:\n            hook_type (str): The type of the hook.\n            *args: Variable length positional arguments.\n            **kwargs: Keyword arguments.\n\n        Returns:\n            The return value of the hook function, if any.\n        \"\"\"\n        hook = self.hooks.get(hook_type)\n        if hook:\n            if asyncio.iscoroutinefunction(hook):\n                return await hook(*args, **kwargs)\n            else:","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/unclecode/crawl4ai/blob/7e801521428ee12509994d39151006f64055ebe3/crawl4ai/async_crawler_strategy.py#L170-L206","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read `detail` (raw exception message) and the server log line 'Stream crawl error:' with its traceback for the root cause","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","Retry with backoff — transient browser launch races commonly self-heal","Simplify the payload (no custom dispatcher/hooks) to isolate whether config-driven setup code is the trigger"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"# preflight: confirm the service is healthy before streaming\nasync def preflight(client):\n    r = await client.get(\"/health\")\n    r.raise_for_status()\n    return True","typeGuard":null,"tryCatchPattern":"for attempt in range(3):\n    try:\n        crawler, gen, hooks = await setup_stream(...)\n        break\n    except HTTPException as e:\n        if e.status_code == 500 and attempt < 2:\n            await asyncio.sleep(2 ** attempt)  # browser startup races often heal\n            continue\n        raise","preventionTips":["Check /health before long streaming sessions","Watch server logs for 'Stream crawl error:' to catch recurring setup faults early","Keep stream payloads minimal (no exotic dispatcher config) to shrink the setup error surface"],"tags":["http-500","streaming","crawler-pool","setup-error"],"backgroundTag":null,"analyzedSha":"7e801521428ee12509994d39151006f64055ebe3","analyzedAt":"2026-08-14T20:46:20.673Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}