{"record":{"id":"0feddab749e7f5dc","repo":"unclecode/crawl4ai","slug":"authentication-failed-str-e","errorCode":null,"errorMessage":"Authentication failed: {str(e)}","messagePattern":"Authentication failed: (.+?)","errorType":"exception","errorClass":"ConnectionError","httpStatus":null,"severity":"error","filePath":"crawl4ai/docker_client.py","lineNumber":63,"sourceCode":"            headers={\"Content-Type\": \"application/json\"}\n        )\n        self._token: Optional[str] = None\n\n    async def authenticate(self, email: str) -> None:\n        \"\"\"Authenticate with the server and store the token.\"\"\"\n        url = urljoin(self.base_url, \"/token\")\n        try:\n            self.logger.info(f\"Authenticating with email: {email}\", tag=\"AUTH\")\n            response = await self._http_client.post(url, json={\"email\": email})\n            response.raise_for_status()\n            data = response.json()\n            self._token = data[\"access_token\"]\n            self._http_client.headers[\"Authorization\"] = f\"Bearer {self._token}\"\n            self.logger.success(\"Authentication successful\", tag=\"AUTH\")\n        except (httpx.RequestError, httpx.HTTPStatusError) as e:\n            error_msg = f\"Authentication failed: {str(e)}\"\n            self.logger.error(error_msg, tag=\"ERROR\")\n            raise ConnectionError(error_msg)\n\n    async def _check_server(self) -> None:\n        \"\"\"Check if server is reachable, raising an error if not.\"\"\"\n        try:\n            await self._http_client.get(urljoin(self.base_url, \"/health\"))\n            self.logger.success(f\"Connected to {self.base_url}\", tag=\"READY\")\n        except httpx.RequestError as e:\n            self.logger.error(f\"Server unreachable: {str(e)}\", tag=\"ERROR\")\n            raise ConnectionError(f\"Cannot connect to server: {str(e)}\")\n\n    def _prepare_request(\n        self,\n        urls: List[str],\n        browser_config: Optional[BrowserConfig] = None,\n        crawler_config: Optional[CrawlerRunConfig] = None,\n        hooks: Optional[Union[Dict[str, Callable], Dict[str, str]]] = None,\n        hooks_timeout: int = 30\n    ) -> Dict[str, Any]:","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/unclecode/crawl4ai/blob/7e801521428ee12509994d39151006f64055ebe3/crawl4ai/docker_client.py#L45-L81","documentation":"Raised by Crawl4aiDockerClient authentication when the POST {base_url}/token request fails at the transport level or returns a non-2xx status (httpx.RequestError or httpx.HTTPStatusError). The underlying cause is wrapped into a ConnectionError with the original httpx message, so the detail string is the authoritative clue.","triggerScenarios":"Calling the client's authenticate/email-token flow when the Docker/server instance is unreachable, base_url points to the wrong host or port, TLS is misconfigured, or the /token endpoint rejects the request (e.g. 4xx because the email payload is refused).","commonSituations":"The crawl4ai server container is not running or is still starting up; base_url uses http:// against an https endpoint or a wrong port; DNS/firewall blocks the host; a reverse proxy in front of the server strips or rejects the /token route.","solutions":["Verify the server is up first: curl {base_url}/health should return 200","Check base_url spelling, scheme, and port against the container's published port","Read str(e) inside the message — 'ConnectError' means unreachable host, '401/404/422' means the endpoint exists but rejected the request","If the server logs show token-endpoint errors, restart or reconfigure the crawl4ai Docker server image"],"exampleFix":"// before\nclient = Crawl4aiDockerClient(base_url=\"http://localhost:11235\")\nawait client.authenticate(\"user@example.com\")  # ConnectionError\n\n// after\n# confirm health first, then authenticate\nimport httpx\nresp = await httpx.AsyncClient().get(\"http://localhost:11235/health\")\nassert resp.status_code == 200, \"start the crawl4ai server container first\"\nawait client.authenticate(\"user@example.com\")","handlingStrategy":"try-catch","validationCode":"import httpx\n\nasync def server_ready(base_url: str) -> bool:\n    try:\n        r = await httpx.AsyncClient().get(f\"{base_url}/health\", timeout=5)\n        return r.status_code == 200\n    except httpx.HTTPError:\n        return False\n\nif not await server_ready(client.base_url):\n    raise RuntimeError(\"crawl4ai server not reachable\")","typeGuard":null,"tryCatchPattern":"try:\n    await client.authenticate(email)\nexcept ConnectionError as e:\n    # str(e) contains the httpx detail: host vs status cause\n    log.error(\"auth failed: %s\", e)\n    raise","preventionTips":["Health-check {base_url}/health before authenticating","Pin the docker server image version to match the client","Surface the embedded httpx detail — it distinguishes unreachable host from rejected request"],"tags":["docker-client","authentication","network"],"backgroundTag":null,"analyzedSha":"7e801521428ee12509994d39151006f64055ebe3","analyzedAt":"2026-08-14T20:46:20.673Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}