{"record":{"id":"dd0a23e1d013e0ab","repo":"BerriAI/litellm","slug":"urn-litellm-error-unknown-query-parameter","errorCode":"urn:litellm:error:unknown-query-parameter","errorMessage":"Unrecognized query parameter(s): {', '.join(unknown)}.","messagePattern":"Unrecognized query parameter\\(s\\): (.+?)\\.","errorType":"http","errorClass":"ManagementProblem","httpStatus":400,"severity":"warning","filePath":"litellm/proxy/management_endpoints/management_v1/common.py","lineNumber":80,"sourceCode":"        type=f\"{PROBLEM_TYPE_BASE}unknown-query-parameter\",\n        title=\"Unknown query parameter\",\n        status=400,\n        detail=f\"Unrecognized query parameter(s): {', '.join(unknown)}.\",\n        allowed=sorted(allowed),\n    )\n\n\nasync def reject_unknown_query_params(request: Request) -> None:\n    \"\"\"Reject any query param the route did not declare.\n\n    A silently ignored filter over-returns data, which is worse than a rejected\n    request; a fresh surface is the only chance to be strict about it.\n    \"\"\"\n    declared: Final = _declared_query_params(request)\n    unknown: Final[tuple[str, ...]] = tuple(sorted(name for name in request.query_params if name not in declared))\n    if not unknown:\n        return\n    raise ManagementProblem(unknown_query_param_problem(unknown=unknown, allowed=tuple(sorted(declared))))\n\n\ndef _page_url(request: Request, page: int) -> str:\n    others: Final = tuple((key, value) for key, value in request.query_params.multi_items() if key != \"page\")\n    return f\"{request.url.path}?{urlencode((*others, ('page', page)))}\"\n\n\ndef build_page_links(request: Request, page: int, has_more: bool) -> PageLinks:\n    return PageLinks(\n        self_link=_page_url(request, page),\n        prev=_page_url(request, page - 1) if page > 1 else None,\n        next=_page_url(request, page + 1) if has_more else None,\n    )\n\n\ndef build_list_links(request: Request, page: int, total_pages: int) -> ListLinks:\n    \"\"\"Page-mode links. `last` clamps to page 1 on an empty result set so every link still resolves.\"\"\"\n    last: Final = max(total_pages, 1)","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/management_endpoints/management_v1/common.py#L62-L98","documentation":"Part of the v1 management API's strict-input contract: reject_unknown_query_params compares every incoming query parameter name against what the route declared and 400s on any extra one. The rationale in code is that a silently ignored filter over-returns data — worse than a rejected request. The response is a problem document (type urn:litellm:error:unknown-query-parameter) naming the unknown parameters and the allowed set.","triggerScenarios":"curl '.../management/v1/budgets?bucket=prod' (no such param); typos like ?pag_size=25, ?sortDirection=desc, or ?organization_id=... on a route that does not declare it; SDK code written against a different (older/newer) route signature.","commonSituations":"Porting integrations from the legacy /key/list-style endpoints whose params differ; version skew between client SDK and proxy; leftover params appended by shared HTTP helper code.","solutions":["Remove or correct the parameter — the error's 'allowed' list (and the endpoint docstring) enumerates exactly what is accepted","Update the client SDK to the matching proxy version so param names line up","For filters, use the declared filter[...] bracket syntax rather than inventing top-level names","Watch for the sibling 'duplicate-query-parameter' problem: each param may appear only once"],"exampleFix":"# before\ncurl 'http://localhost:4000/management/v1/budgets?pag_size=25'   # 400 unknown-query-parameter\n# after\ncurl 'http://localhost:4000/management/v1/budgets?page_size=25'","handlingStrategy":"validation","validationCode":"ALLOWED = {'page', 'page_size', 'sort', 'search'}  # keep per-route, from the endpoint docs\n\ndef clean_query(q: dict) -> dict:\n    unknown = set(q) - ALLOWED\n    if unknown:\n        raise ValueError(f'params not accepted by this route: {sorted(unknown)}; allowed: {sorted(ALLOWED)}')\n    return q","typeGuard":null,"tryCatchPattern":"try:\n    r = await client.get('/management/v1/budgets', params=clean_query(q))\n    r.raise_for_status()\nexcept httpx.HTTPStatusError as e:\n    if 'unknown-query-parameter' in e.response.text:\n        allowed = e.response.json().get('detail', '')   # lists allowed params; adjust q accordingly\n        raise ValueError(f'fix query params: {allowed}') from e\n    raise","preventionTips":["Maintain a per-route allowlist of query params in client code instead of passing dicts through","Use the documented filter[...] bracket syntax for filters, not invented top-level names","Pin SDK and proxy versions together; param sets change across releases"],"tags":["query-params","validation","problem-details","litellm-proxy","management-api"],"backgroundTag":"unknown-query-parameter","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}