{"record":{"id":"6f5e99b41b8f0f66","repo":"unclecode/crawl4ai","slug":"failed-to-evaluate-wait-condition-str-e","errorCode":null,"errorMessage":"Failed to evaluate wait condition: {str(e)}","messagePattern":"Failed to evaluate wait condition: (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"warning","filePath":"crawl4ai/async_crawler_strategy.py","lineNumber":340,"sourceCode":"                        return true;\n                    }}\n                    if (Date.now() - startTime > {timeout}) {{\n                        return false;  // Return false instead of throwing\n                    }}\n                    await new Promise(resolve => setTimeout(resolve, 100));\n                }}\n            }} catch (error) {{\n                throw new Error(`Error evaluating condition: ${{error.message}}`);\n            }}\n        }}\n        \"\"\"\n\n        try:\n            result = await self.adapter.evaluate(page, wrapper_js)\n            return result\n        except Exception as e:\n            if \"Error evaluating condition\" in str(e):\n                raise RuntimeError(f\"Failed to evaluate wait condition: {str(e)}\")\n            # For timeout or other cases, just return False\n            return False\n\n    async def process_iframes(self, page):\n        \"\"\"\n        Process iframes on a page. This function will extract the content of each iframe and replace it with a div containing the extracted content.\n\n        Args:\n            page: Playwright page object\n\n        Returns:\n            Playwright page object\n        \"\"\"\n        # Find all iframes\n        iframes = await page.query_selector_all(\"iframe\")\n\n        for i, iframe in enumerate(iframes):\n            try:","sourceCodeStart":322,"sourceCodeEnd":358,"githubUrl":"https://github.com/unclecode/crawl4ai/blob/7e801521428ee12509994d39151006f64055ebe3/crawl4ai/async_crawler_strategy.py#L322-L358","documentation":"A 400 Bad Request raised during stream-crawl setup when the submitted configuration fails trust validation: crawler_config is loaded via `CrawlerRunConfig.load(..., provenance=Provenance.UNTRUSTED)` and hook configs are validated, so any field or hook the server does not allow for untrusted clients raises UntrustedConfigError or HookValidationError. The crawler instance is released and the rejection message is echoed back.","triggerScenarios":"POSTing to the stream endpoint with a crawler_config key that the server's untrusted-allowlist rejects (e.g. arbitrary callable, internal-only option) or a hooks_config that fails HookValidationError (bad event name, invalid hook spec).","commonSituations":"Porting a local script's full config object to the HTTP API without pruning server-side-only fields; upgrading the server so a previously accepted option moves off the untrusted allowlist; sending hooks with wrong schema.","solutions":["Read the detail text — it names the exact rejected field/hook; remove or correct that key","Send only allowlisted crawler_config fields for untrusted clients; run admin/local mode if the option is genuinely needed","Validate hooks_config against the documented hook schema (event names, signatures) before submitting"],"exampleFix":"# before\npayload = {\"urls\": [u], \"crawler_config\": {\"browser_agent\": \"...\", \"verbose\": True, \"magic\": True}}\n\n# after\npayload = {\"urls\": [u], \"crawler_config\": {\"browser_agent\": \"...\"}}  # only allowlisted keys","handlingStrategy":"validation","validationCode":"ALLOWED_CRAWLER_KEYS = {\"word_count_threshold\", \"only_text\", \"screenshot\", \"pdf\"}\ndef sanitize(cfg):\n    bad = set(cfg) - ALLOWED_CRAWLER_KEYS\n    if bad:\n        raise ValueError(f\"untrusted config rejects: {bad}\")\n    return cfg","typeGuard":null,"tryCatchPattern":"try:\n    crawler, gen, hooks = await setup_stream(urls, browser_cfg, crawler_cfg, hooks_cfg)\nexcept HTTPException as e:\n    if e.status_code == 400:\n        report_config_rejection(e.detail)  # name the rejected key to the user\n    raise","preventionTips":["Keep a client-side allowlist mirroring the server's untrusted config allowlist","Validate hooks_config schema (event names, signatures) before submitting","Log the 400 detail verbatim; it names the offending field"],"tags":["http-400","config-validation","untrusted-config","hooks"],"backgroundTag":null,"analyzedSha":"7e801521428ee12509994d39151006f64055ebe3","analyzedAt":"2026-08-14T20:46:20.673Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}