{"record":{"id":"84242eb71a2885ab","repo":"BerriAI/litellm","slug":"please-provide-start-date-and-end-date","errorCode":null,"errorMessage":"Please provide start_date and end_date","messagePattern":"Please provide start_date and end_date","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"litellm/proxy/management_endpoints/common_daily_activity.py","lineNumber":1010,"sourceCode":"    resolve_entity_metadata: Callable[[Sequence[DailySpendRecord]], Awaitable[dict[str, dict[str, object]]]]\n    | None = None,\n) -> SpendAnalyticsPaginatedResponse:\n    \"\"\"Common function to get daily activity for any entity type.\n\n    ``resolve_entity_metadata`` lets a caller resolve entity metadata from the\n    rows actually on the page (e.g. user_id -> user_email) instead of fetching\n    the whole entity table upfront, which matters when the entity set is\n    unbounded.\n    \"\"\"\n\n    if prisma_client is None:\n        raise HTTPException(\n            status_code=500,\n            detail={\"error\": CommonProxyErrors.db_not_connected_error.value},\n        )\n\n    if start_date is None or end_date is None:\n        raise HTTPException(\n            status_code=status.HTTP_400_BAD_REQUEST,\n            detail={\"error\": \"Please provide start_date and end_date\"},\n        )\n\n    try:\n        where_conditions: Final = _build_where_conditions(\n            entity_id_field=entity_id_field,\n            entity_id=entity_id,\n            start_date=start_date,\n            end_date=end_date,\n            model=model,\n            api_key=api_key,\n            exclude_entity_ids=exclude_entity_ids,\n            timezone_offset_minutes=timezone_offset_minutes,\n            include_current_utc_day=include_current_utc_day,\n        )\n\n        # Get total count for pagination","sourceCodeStart":992,"sourceCodeEnd":1028,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/management_endpoints/common_daily_activity.py#L992-L1028","documentation":"get_daily_activity requires an explicit query window: if start_date or end_date is None it raises HTTP 400 'Please provide start_date and end_date'. The dates are parsed downstream (dateutil/SQL), so any parsable string works, but they must be present — there is no default range. This check runs after the DB check, so a 400 here means the DB is fine and only the query params are missing.","triggerScenarios":"Calling any daily-activity/spend endpoint without ?start_date=...&end_date=...; passing only one bound of the range; passing an empty string (parsed as absent by the endpoint's query handling).","commonSituations":"Dashboard code that builds URLs conditionally and omits params for 'all time'; copied curl examples with the dates stripped; time-zone-aware clients sending dates under differently named params (startDate vs start_date).","solutions":["Add both query parameters, e.g. ?start_date=2026-08-01&end_date=2026-08-18","Use the exact snake_case parameter names start_date and end_date","For 'all time', compute a wide explicit range client-side rather than omitting the params"],"exampleFix":"# before\ncurl http://localhost:4000/global/spend -H \"Authorization: Bearer $KEY\"  # 400 Please provide start_date and end_date\n\n# after\ncurl \"http://localhost:4000/global/spend?start_date=2026-08-01&end_date=2026-08-18\" -H \"Authorization: Bearer $KEY\"","handlingStrategy":"validation","validationCode":"from datetime import datetime, timezone\n\ndef make_params(start: str, end: str) -> dict:\n    # Fail before the call if either bound is missing or unparsable\n    if not start or not end:\n        raise ValueError(\"start_date and end_date are both required\")\n    datetime.fromisoformat(start)\n    datetime.fromisoformat(end)\n    return {\"start_date\": start, \"end_date\": end}","typeGuard":"from typing import TypeGuard\n\ndef has_date_range(params: dict) -> TypeGuard[dict]:\n    \"\"\"True when params carry non-empty, ISO-formatted start/end dates.\"\"\"\n    for k in (\"start_date\", \"end_date\"):\n        v = params.get(k)\n        if not isinstance(v, str) or not v:\n            return False\n        try:\n            datetime.fromisoformat(v)\n        except ValueError:\n            return False\n    return True","tryCatchPattern":"import httpx\n\ntry:\n    r = httpx.get(f\"{PROXY_URL}/global/spend\", params=params, headers=hdrs)\n    r.raise_for_status()\nexcept httpx.HTTPStatusError as e:\n    if e.response.status_code == 400 and \"start_date and end_date\" in e.response.text:\n        params.update({\"start_date\": DEFAULT_START, \"end_date\": today_iso()})\n        r = httpx.get(f\"{PROXY_URL}/global/spend\", params=params, headers=hdrs)\n        r.raise_for_status()\n    else:\n        raise","preventionTips":["Build analytics URLs from a helper that always injects both dates","Use ISO 8601 (YYYY-MM-DD) everywhere to also avoid the downstream 500 parse error"],"tags":["litellm-proxy","validation","query-params","spend-analytics","dates"],"backgroundTag":"missing-required-parameter","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}