unclecode/crawl4ai · error · HTTPException
Query parameter 'q' is required
Error message
Query parameter 'q' is required
What it means
A 400 from GET /llm/{url}: the required query parameter q (the question for LLM-based QA over the page) was missing, empty, or blank. The route declares q: str = Query(...) so FastAPI normally enforces presence, but an empty string ('?q=') passes FastAPI and is caught by this explicit `if not q` check.
Source
Thrown at deploy/docker/server.py:821
raise HTTPException(500, detail=str(e))
finally:
if crawler:
await release_crawler(crawler)
@app.get("/llm/{url:path}")
async def llm_endpoint(
request: Request,
url: str = Path(...),
q: str = Query(...),
provider: Optional[str] = Query(None, description="LLM provider override, e.g. 'openai/gpt-4o-mini'"),
temperature: Optional[float] = Query(None, description="LLM temperature override"),
_td: Dict = Depends(token_dep),
):
# base_url is intentionally not accepted (key-exfil vector); the endpoint is
# derived server-side from the provider name only.
if not q:
raise HTTPException(400, "Query parameter 'q' is required")
if not url.startswith(("http://", "https://")) and not url.startswith(("raw:", "raw://")):
url = "https://" + url
answer = await handle_llm_qa(url, q, config, provider=provider, temperature=temperature)
return JSONResponse({"answer": answer})
@app.get("/schema")
async def get_schema():
from crawl4ai import BrowserConfig, CrawlerRunConfig
return {"browser": BrowserConfig().dump(),
"crawler": CrawlerRunConfig().dump()}
@app.get("/hooks/info")
async def get_hooks_info():
"""Enumerate the available declarative hook actions and their parameter schemas.
Arbitrary hook code is no longer accepted (it was an exec()-based RCEView on GitHub (pinned to 7e80152142)
Solutions
- Include a non-empty q: GET /llm/https://example.com/page?q=summarize%20the%20article.
- Client-side, refuse to call the endpoint when the question string is empty.
- If you see 422 instead, the parameter was absent entirely — same fix.
Example fix
# before
requests.get(f'{base}/llm/{url}')
# after
if not q.strip():
raise ValueError('question required')
requests.get(f'{base}/llm/{url}', params={'q': q}) Defensive patterns
Strategy: validation
Validate before calling
from urllib.parse import urlencode
def llm_url(base: str, url: str, q: str) -> str:
if not q or not q.strip():
raise ValueError("query 'q' must be a non-empty question")
return f'{base}/llm/{url}?{urlencode({"q": q})}' Type guard
def has_question(q: str | None) -> bool:
return isinstance(q, str) and len(q.strip()) > 0 Prevention
- Validate q client-side before building the URL.
- Use params= with an HTTP client instead of hand-concatenating query strings.
- Treat both 400 (empty q) and 422 (missing q) as the same fix: supply a real question.
When it happens
Trigger: GET /llm/https://example.com/page without a q parameter (FastAPI 422 normally) or with q= (empty value → this 400). Also q=%20 (whitespace-only still truthy, so passes — only truly empty values hit this).
Common situations: Clients building the query string manually and dropping q when the user asked no question; template strings leaving q empty; URL-encoding bugs that truncate parameters.
Related errors
- Container not found: ${config.container_selector}
- str(e)
- error_msg
- str(e)
- Invalid status: {status}. Must be one of: all, active, compl
AI-assisted analysis of unclecode/crawl4ai@7e80152142 (2026-08-14).
Data as JSON: /api/errors/5b2e2edc30010372.
Report an issue: GitHub.