unclecode/crawl4ai · error · HTTPException
Invalid email domain
Error message
Invalid email domain
What it means
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.
Source
Thrown at deploy/docker/server.py:547
status_code=500,
)
# ──────────────────────── Endpoints ──────────────────────────
@app.post("/token")
async def get_token(req: TokenRequest):
expected_token = config.get("security", {}).get("api_token", "")
if not expected_token:
# Fail closed: without a configured api_token the old behavior minted a
# JWT to anyone whose email merely had an MX record. Refuse instead.
raise HTTPException(
403,
"Token issuance is disabled: no api_token is configured on the server.",
)
if not req.api_token or not constant_time_eq(req.api_token, expected_token):
raise HTTPException(401, "Invalid or missing api_token")
if not verify_email_domain(req.email):
raise HTTPException(400, "Invalid email domain")
token = create_access_token({"sub": req.email})
return {"email": req.email, "access_token": token, "token_type": "bearer"}
@app.post("/config/dump")
async def config_dump(
data: dict,
_td: Dict = Depends(token_dep),
):
try:
return JSONResponse(_config_from_json(data))
except (TypeError, ValueError) as e:
raise HTTPException(400, str(e))
@app.post("/md")
@limiter.limit(config["rate_limiting"]["default_limit"])
@mcp_tool("md")View on GitHub (pinned to 7e80152142)
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.
Example fix
// before
await client.post('/token', json={'api_token': tok, 'email': 'user@test.invalid'})
// after
await client.post('/token', json={'api_token': tok, 'email': 'user@example.com'}) // example.com has MX records Defensive patterns
Strategy: validation
Validate before calling
import dns.resolver # dnspython
def email_domain_ok(email: str) -> bool:
domain = email.rsplit('@', 1)[-1]
if '.' not in domain or ' ' in email:
return False
try:
dns.resolver.resolve(domain, 'MX')
return True
except Exception:
return False
assert email_domain_ok('user@example.com') Try / catch
try:
tok = await client.post('/token', json={'api_token': t, 'email': e})
except httpx.HTTPStatusError as exc:
if exc.response.status_code == 400:
# domain rejected: fix the email, do not retry blindly
raise ValueError(f'bad email domain: {e}') from exc
if exc.response.status_code == 403:
raise RuntimeError('no api_token configured on server') from exc
raise Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Container not found: ${config.container_selector}
- Timeout after {timeout}ms waiting for selector '{wait_for}'
- Unsupported export format: {format}
- [NSTProxy] token and channel_id are required
- [NSTProxy] Invalid protocol: {protocol}
AI-assisted analysis of unclecode/crawl4ai@7e80152142 (2026-08-14).
Data as JSON: /api/errors/f03bbb1142baadc5.
Report an issue: GitHub.