{"record":{"id":"bc5c0fe14fac77d8","repo":"BerriAI/litellm","slug":"failed-to-fetch-analytics-e","errorCode":null,"errorMessage":"Failed to fetch analytics: {e}","messagePattern":"Failed to fetch analytics: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"error","filePath":"litellm/proxy/management_endpoints/common_daily_activity.py","lineNumber":1094,"sourceCode":"                total_tokens=metadata_metrics.total_tokens,\n                total_api_requests=metadata_metrics.api_requests,\n                total_successful_requests=metadata_metrics.successful_requests,\n                total_failed_requests=metadata_metrics.failed_requests,\n                total_cache_read_input_tokens=metadata_metrics.cache_read_input_tokens,\n                total_cache_creation_input_tokens=metadata_metrics.cache_creation_input_tokens,\n                total_compression_saved_tokens=metadata_metrics.compression_saved_tokens,\n                total_compression_savings_spend=metadata_metrics.compression_savings_spend,\n                total_prompt_caching_savings_spend=metadata_metrics.prompt_caching_savings_spend,\n                total_autorouter_savings_spend=metadata_metrics.autorouter_savings_spend,\n                page=page,\n                total_pages=-(-total_count // page_size),  # Ceiling division\n                has_more=(page * page_size) < total_count,\n            ),\n        )\n\n    except Exception as e:\n        verbose_proxy_logger.exception(\"Error fetching daily activity: %s\", e)\n        raise HTTPException(\n            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,\n            detail={\"error\": f\"Failed to fetch analytics: {e}\"},\n        )\n\n\nasync def get_daily_activity_aggregated(\n    prisma_client: PrismaClient | None,\n    table_name: str,\n    entity_id_field: str,\n    entity_id: str | list[str] | None,\n    entity_metadata_field: Mapping[str, dict[str, object]] | None,\n    start_date: str | None,\n    end_date: str | None,\n    model: str | None,\n    api_key: str | None,\n    exclude_entity_ids: list[str] | None = None,\n    timezone_offset_minutes: int | None = None,\n) -> SpendAnalyticsPaginatedResponse:","sourceCodeStart":1076,"sourceCodeEnd":1112,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/management_endpoints/common_daily_activity.py#L1076-L1112","documentation":"This is the catch-all of get_daily_activity: every step after the guards (building WHERE conditions, the count query, the paginated spend query, metadata resolution, metrics aggregation) runs inside try/except; any exception is logged by verbose_proxy_logger as 'Error fetching daily activity: <e>' and re-raised as HTTP 500 'Failed to fetch analytics: <e}'. The interpolated text is the real cause — typical ones are unparsable date strings reaching dateutil, SQL/Prisma errors, or unexpected None fields in spend rows during aggregation.","triggerScenarios":"Passing a start_date/end_date value that is present but not date-parsable (e.g. '2026-13-45' or 'yesterday-ish'); DB errors mid-query (connection drop, permission on spend tables); malformed api_key/model filter values that break SQL parameter binding.","commonSituations":"Datepickers emitting locale-specific formats; long-running analytics queries hitting connection pool timeouts; schemas drifted after restoring a backup so spend tables lack expected columns.","solutions":["Read the 'Failed to fetch analytics: <e>' detail — it names the actual exception","If date-related: normalize dates to ISO 8601 (YYYY-MM-DD) client-side and retry","If DB-related: check Postgres health, proxy logs for the full stack trace, and that migrations ran for the spend tables","Narrow the date window or add filters (model, api_key) to reduce query size if timeouts are the cause"],"exampleFix":"# before\ncurl \"...?start_date=Aug 1, 2026&end_date=18/08/2026\"  # 500 Failed to fetch analytics\n\n# after\ncurl \"...?start_date=2026-08-01&end_date=2026-08-18\"  # 200","handlingStrategy":"retry","validationCode":"from datetime import datetime\n\ndef valid_analytics_params(params: dict) -> bool:\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\n\nassert valid_analytics_params(params), \"dates must be present and ISO-formatted\"","typeGuard":null,"tryCatchPattern":"import httpx, time\n\ndef fetch_daily_activity(url, hdrs, params, attempts=3):\n    last = None\n    for i in range(attempts):\n        try:\n            r = httpx.get(url, params=params, headers=hdrs, timeout=60)\n            if r.status_code == 200:\n                return r.json()\n            if r.status_code == 500 and \"Failed to fetch analytics\" in r.text:\n                last = r.text  # root cause is interpolated + logged server-side\n                time.sleep(2 ** i)\n                continue\n            r.raise_for_status()\n        except httpx.TransportError as e:\n            last = str(e)\n            time.sleep(2 ** i)\n    raise RuntimeError(f\"daily activity fetch failed: {last}\")","preventionTips":["Normalize all dates to ISO 8601 before sending","Cap analytics windows so GROUP BY queries stay under DB timeouts","Read the server-side stack trace ('Error fetching daily activity') before retrying"],"tags":["litellm-proxy","spend-analytics","internal-error","dates","database"],"backgroundTag":"internal-server-error","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}