unclecode/crawl4ai · error · ConnectionError

Authentication failed: {str(e)}

Error message

Authentication failed: {str(e)}

What it means

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.

Source

Thrown at crawl4ai/docker_client.py:63

            headers={"Content-Type": "application/json"}
        )
        self._token: Optional[str] = None

    async def authenticate(self, email: str) -> None:
        """Authenticate with the server and store the token."""
        url = urljoin(self.base_url, "/token")
        try:
            self.logger.info(f"Authenticating with email: {email}", tag="AUTH")
            response = await self._http_client.post(url, json={"email": email})
            response.raise_for_status()
            data = response.json()
            self._token = data["access_token"]
            self._http_client.headers["Authorization"] = f"Bearer {self._token}"
            self.logger.success("Authentication successful", tag="AUTH")
        except (httpx.RequestError, httpx.HTTPStatusError) as e:
            error_msg = f"Authentication failed: {str(e)}"
            self.logger.error(error_msg, tag="ERROR")
            raise ConnectionError(error_msg)

    async def _check_server(self) -> None:
        """Check if server is reachable, raising an error if not."""
        try:
            await self._http_client.get(urljoin(self.base_url, "/health"))
            self.logger.success(f"Connected to {self.base_url}", tag="READY")
        except httpx.RequestError as e:
            self.logger.error(f"Server unreachable: {str(e)}", tag="ERROR")
            raise ConnectionError(f"Cannot connect to server: {str(e)}")

    def _prepare_request(
        self,
        urls: List[str],
        browser_config: Optional[BrowserConfig] = None,
        crawler_config: Optional[CrawlerRunConfig] = None,
        hooks: Optional[Union[Dict[str, Callable], Dict[str, str]]] = None,
        hooks_timeout: int = 30
    ) -> Dict[str, Any]:

View on GitHub (pinned to 7e80152142)

Solutions

  1. Verify the server is up first: curl {base_url}/health should return 200
  2. Check base_url spelling, scheme, and port against the container's published port
  3. Read str(e) inside the message — 'ConnectError' means unreachable host, '401/404/422' means the endpoint exists but rejected the request
  4. If the server logs show token-endpoint errors, restart or reconfigure the crawl4ai Docker server image

Example fix

// before
client = Crawl4aiDockerClient(base_url="http://localhost:11235")
await client.authenticate("user@example.com")  # ConnectionError

// after
# confirm health first, then authenticate
import httpx
resp = await httpx.AsyncClient().get("http://localhost:11235/health")
assert resp.status_code == 200, "start the crawl4ai server container first"
await client.authenticate("user@example.com")
Defensive patterns

Strategy: try-catch

Validate before calling

import httpx

async def server_ready(base_url: str) -> bool:
    try:
        r = await httpx.AsyncClient().get(f"{base_url}/health", timeout=5)
        return r.status_code == 200
    except httpx.HTTPError:
        return False

if not await server_ready(client.base_url):
    raise RuntimeError("crawl4ai server not reachable")

Try / catch

try:
    await client.authenticate(email)
except ConnectionError as e:
    # str(e) contains the httpx detail: host vs status cause
    log.error("auth failed: %s", e)
    raise

Prevention

When it happens

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

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

Understand the failure class

Related errors


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