{"record":{"id":"f03bbb1142baadc5","repo":"unclecode/crawl4ai","slug":"invalid-email-domain","errorCode":null,"errorMessage":"Invalid email domain","messagePattern":"Invalid email domain","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"deploy/docker/server.py","lineNumber":547,"sourceCode":"        status_code=500,\n    )\n\n\n# ──────────────────────── Endpoints ──────────────────────────\n@app.post(\"/token\")\nasync def get_token(req: TokenRequest):\n    expected_token = config.get(\"security\", {}).get(\"api_token\", \"\")\n    if not expected_token:\n        # Fail closed: without a configured api_token the old behavior minted a\n        # JWT to anyone whose email merely had an MX record. Refuse instead.\n        raise HTTPException(\n            403,\n            \"Token issuance is disabled: no api_token is configured on the server.\",\n        )\n    if not req.api_token or not constant_time_eq(req.api_token, expected_token):\n        raise HTTPException(401, \"Invalid or missing api_token\")\n    if not verify_email_domain(req.email):\n        raise HTTPException(400, \"Invalid email domain\")\n    token = create_access_token({\"sub\": req.email})\n    return {\"email\": req.email, \"access_token\": token, \"token_type\": \"bearer\"}\n\n\n@app.post(\"/config/dump\")\nasync def config_dump(\n    data: dict,\n    _td: Dict = Depends(token_dep),\n):\n    try:\n        return JSONResponse(_config_from_json(data))\n    except (TypeError, ValueError) as e:\n        raise HTTPException(400, str(e))\n\n\n@app.post(\"/md\")\n@limiter.limit(config[\"rate_limiting\"][\"default_limit\"])\n@mcp_tool(\"md\")","sourceCodeStart":529,"sourceCodeEnd":565,"githubUrl":"https://github.com/unclecode/crawl4ai/blob/7e801521428ee12509994d39151006f64055ebe3/deploy/docker/server.py#L529-L565","documentation":"Thrown by the /token endpoint when verify_email_domain() rejects the supplied email's domain. The server only mints JWTs for emails whose domain passes validation (typically MX-record / format checks). It is a 400: the request itself is well-formed but the email domain is not acceptable.","triggerScenarios":"POST /token with an api_token that matches the configured security.api_token but an email whose domain has no MX record, is syntactically invalid, or is on the server's deny list. Note issuance also fails closed with 403 if no api_token is configured at all — that is a different error.","commonSituations":"Developer points the client at a server with a correct api_token but types a typo'd or disposable email domain (e.g. 'user@localhost', 'user@nonexistent-domain'); corporate domains with unusual DNS setups; a config where api_token is set but the email used in automated tests is fake.","solutions":["Use an email address at a real domain with valid MX records (e.g. you@yourcompany.com).","Check the domain externally: `dig MX yourdomain.com` — if no MX record exists, pick another domain.","Inspect verify_email_domain() in the server source to see the exact rules (deny list, DNS timeout) and satisfy them.","If this is CI/automated use, configure a fixed email at a domain you control with MX records."],"exampleFix":"// before\nawait client.post('/token', json={'api_token': tok, 'email': 'user@test.invalid'})\n// after\nawait client.post('/token', json={'api_token': tok, 'email': 'user@example.com'})  // example.com has MX records","handlingStrategy":"validation","validationCode":"import dns.resolver  # dnspython\n\ndef email_domain_ok(email: str) -> bool:\n    domain = email.rsplit('@', 1)[-1]\n    if '.' not in domain or ' ' in email:\n        return False\n    try:\n        dns.resolver.resolve(domain, 'MX')\n        return True\n    except Exception:\n        return False\n\nassert email_domain_ok('user@example.com')","typeGuard":null,"tryCatchPattern":"try:\n    tok = await client.post('/token', json={'api_token': t, 'email': e})\nexcept httpx.HTTPStatusError as exc:\n    if exc.response.status_code == 400:\n        # domain rejected: fix the email, do not retry blindly\n        raise ValueError(f'bad email domain: {e}') from exc\n    if exc.response.status_code == 403:\n        raise RuntimeError('no api_token configured on server') from exc\n    raise","preventionTips":["Always send an email at a domain you control with valid MX records.","Distinguish 403 (server has no api_token configured) from 400 (domain rejected) in client handling — they have different fixes.","Cache the token; don't re-run /token per request, reducing exposure to this check."],"tags":["auth","email","dns","validation"],"backgroundTag":null,"analyzedSha":"7e801521428ee12509994d39151006f64055ebe3","analyzedAt":"2026-08-14T20:46:20.673Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}