unclecode/crawl4ai · warning · RuntimeError

Failed to evaluate wait condition: {str(e)}

Error message

Failed to evaluate wait condition: {str(e)}

What it means

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.

Source

Thrown at crawl4ai/async_crawler_strategy.py:340

                        return true;
                    }}
                    if (Date.now() - startTime > {timeout}) {{
                        return false;  // Return false instead of throwing
                    }}
                    await new Promise(resolve => setTimeout(resolve, 100));
                }}
            }} catch (error) {{
                throw new Error(`Error evaluating condition: ${{error.message}}`);
            }}
        }}
        """

        try:
            result = await self.adapter.evaluate(page, wrapper_js)
            return result
        except Exception as e:
            if "Error evaluating condition" in str(e):
                raise RuntimeError(f"Failed to evaluate wait condition: {str(e)}")
            # For timeout or other cases, just return False
            return False

    async def process_iframes(self, page):
        """
        Process iframes on a page. This function will extract the content of each iframe and replace it with a div containing the extracted content.

        Args:
            page: Playwright page object

        Returns:
            Playwright page object
        """
        # Find all iframes
        iframes = await page.query_selector_all("iframe")

        for i, iframe in enumerate(iframes):
            try:

View on GitHub (pinned to 7e80152142)

Solutions

  1. Read the detail text — it names the exact rejected field/hook; remove or correct that key
  2. Send only allowlisted crawler_config fields for untrusted clients; run admin/local mode if the option is genuinely needed
  3. Validate hooks_config against the documented hook schema (event names, signatures) before submitting

Example fix

# before
payload = {"urls": [u], "crawler_config": {"browser_agent": "...", "verbose": True, "magic": True}}

# after
payload = {"urls": [u], "crawler_config": {"browser_agent": "..."}}  # only allowlisted keys
Defensive patterns

Strategy: validation

Validate before calling

ALLOWED_CRAWLER_KEYS = {"word_count_threshold", "only_text", "screenshot", "pdf"}
def sanitize(cfg):
    bad = set(cfg) - ALLOWED_CRAWLER_KEYS
    if bad:
        raise ValueError(f"untrusted config rejects: {bad}")
    return cfg

Try / catch

try:
    crawler, gen, hooks = await setup_stream(urls, browser_cfg, crawler_cfg, hooks_cfg)
except HTTPException as e:
    if e.status_code == 400:
        report_config_rejection(e.detail)  # name the rejected key to the user
    raise

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


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