{"record":{"id":"830bc2ac9de95769","repo":"unclecode/crawl4ai","slug":"invalid-css-selector-css-selector","errorCode":null,"errorMessage":"Invalid CSS selector: '{css_selector}'","messagePattern":"Invalid CSS selector: '(.+?)'","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"warning","filePath":"crawl4ai/async_crawler_strategy.py","lineNumber":269,"sourceCode":"        \"\"\"\n        wait_for = wait_for.strip()\n\n        if wait_for.startswith(\"js:\"):\n            # Explicitly specified JavaScript\n            js_code = wait_for[3:].strip()\n            return await self.csp_compliant_wait(page, js_code, timeout)\n        elif wait_for.startswith(\"css:\"):\n            # Explicitly specified CSS selector\n            css_selector = wait_for[4:].strip()\n            try:\n                await page.wait_for_selector(css_selector, timeout=timeout)\n            except Error as e:\n                if \"Timeout\" in str(e):\n                    raise TimeoutError(\n                        f\"Timeout after {timeout}ms waiting for selector '{css_selector}'\"\n                    )\n                else:\n                    raise ValueError(f\"Invalid CSS selector: '{css_selector}'\")\n        else:\n            # Auto-detect based on content\n            if wait_for.startswith(\"()\") or wait_for.startswith(\"function\"):\n                # It's likely a JavaScript function\n                return await self.csp_compliant_wait(page, wait_for, timeout)\n            else:\n                # Assume it's a CSS selector first\n                try:\n                    await page.wait_for_selector(wait_for, timeout=timeout)\n                except Error as e:\n                    if \"Timeout\" in str(e):\n                        raise TimeoutError(\n                            f\"Timeout after {timeout}ms waiting for selector '{wait_for}'\"\n                        )\n                    else:\n                        # If it's not a timeout error, it might be an invalid selector\n                        # Let's try to evaluate it as a JavaScript function as a fallback\n                        try:","sourceCodeStart":251,"sourceCodeEnd":287,"githubUrl":"https://github.com/unclecode/crawl4ai/blob/7e801521428ee12509994d39151006f64055ebe3/crawl4ai/async_crawler_strategy.py#L251-L287","documentation":"QuotaExceeded is raised by write_artifact when adding this artifact would push the total on-disk size of the artifact store past ARTIFACT_QUOTA_BYTES (env CRAWL4AI_ARTIFACT_QUOTA_BYTES, default 2 GiB). Unlike the per-item cap, this is a shared budget across all stored artifacts; expired artifacts are reaped by a janitor, so the quota is recoverable.","triggerScenarios":"Storing an artifact when _dir_size() + len(data) > 2 GiB (or configured quota) — e.g. sustained crawl runs generating screenshots/PDFs until the store fills, with the TTL (default 1 h) not yet expiring old entries.","commonSituations":"High-throughput batch crawls producing many media artifacts; a low quota set for a small disk; janitor not running often enough so expired artifacts still count toward the measured size.","solutions":["Trigger or wait for the janitor/TTL sweep (expired artifacts are unlinked, freeing quota) and retry","Raise CRAWL4AI_ARTIFACT_QUOTA_BYTES if the volume is legitimate and disk allows","Lower CRAWL4AI_TTL (CRAWL4AI_ARTIFACT_TTL_SECONDS) so artifacts age out faster under sustained load"],"exampleFix":"# server: free quota via janitor endpoint/call, or raise budget\n# docker-compose.yml\nenvironment:\n  CRAWL4AI_ARTIFACT_QUOTA_BYTES: \"5368709120\"  # 5 GiB\n  CRAWL4AI_ARTIFACT_TTL_SECONDS: \"1800\"","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"from artifacts import write_artifact, QuotaExceeded\ntry:\n    meta = write_artifact(kind, data)\nexcept QuotaExceeded:\n    janitor()  # reap expired artifacts to free budget\n    meta = write_artifact(kind, data)  # one bounded retry","preventionTips":["Run/schedule the janitor regularly under sustained artifact-producing load","Monitor store size against CRAWL4AI_ARTIFACT_QUOTA_BYTES and alert before it fills","Set TTL short enough that artifact production rate x TTL stays under quota"],"tags":["artifacts","quota","disk","configuration"],"backgroundTag":null,"analyzedSha":"7e801521428ee12509994d39151006f64055ebe3","analyzedAt":"2026-08-14T20:46:20.673Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}