BerriAI/litellm · error · HTTPException
Failed to fetch analytics: {e}
Error message
Failed to fetch analytics: {e} What it means
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.
Source
Thrown at litellm/proxy/management_endpoints/common_daily_activity.py:1094
total_tokens=metadata_metrics.total_tokens,
total_api_requests=metadata_metrics.api_requests,
total_successful_requests=metadata_metrics.successful_requests,
total_failed_requests=metadata_metrics.failed_requests,
total_cache_read_input_tokens=metadata_metrics.cache_read_input_tokens,
total_cache_creation_input_tokens=metadata_metrics.cache_creation_input_tokens,
total_compression_saved_tokens=metadata_metrics.compression_saved_tokens,
total_compression_savings_spend=metadata_metrics.compression_savings_spend,
total_prompt_caching_savings_spend=metadata_metrics.prompt_caching_savings_spend,
total_autorouter_savings_spend=metadata_metrics.autorouter_savings_spend,
page=page,
total_pages=-(-total_count // page_size), # Ceiling division
has_more=(page * page_size) < total_count,
),
)
except Exception as e:
verbose_proxy_logger.exception("Error fetching daily activity: %s", e)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail={"error": f"Failed to fetch analytics: {e}"},
)
async def get_daily_activity_aggregated(
prisma_client: PrismaClient | None,
table_name: str,
entity_id_field: str,
entity_id: str | list[str] | None,
entity_metadata_field: Mapping[str, dict[str, object]] | None,
start_date: str | None,
end_date: str | None,
model: str | None,
api_key: str | None,
exclude_entity_ids: list[str] | None = None,
timezone_offset_minutes: int | None = None,
) -> SpendAnalyticsPaginatedResponse:View on GitHub (pinned to 77b7c6c40c)
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
Example fix
# before curl "...?start_date=Aug 1, 2026&end_date=18/08/2026" # 500 Failed to fetch analytics # after curl "...?start_date=2026-08-01&end_date=2026-08-18" # 200
Defensive patterns
Strategy: retry
Validate before calling
from datetime import datetime
def valid_analytics_params(params: dict) -> bool:
for k in ("start_date", "end_date"):
v = params.get(k)
if not isinstance(v, str) or not v:
return False
try:
datetime.fromisoformat(v)
except ValueError:
return False
return True
assert valid_analytics_params(params), "dates must be present and ISO-formatted" Try / catch
import httpx, time
def fetch_daily_activity(url, hdrs, params, attempts=3):
last = None
for i in range(attempts):
try:
r = httpx.get(url, params=params, headers=hdrs, timeout=60)
if r.status_code == 200:
return r.json()
if r.status_code == 500 and "Failed to fetch analytics" in r.text:
last = r.text # root cause is interpolated + logged server-side
time.sleep(2 ** i)
continue
r.raise_for_status()
except httpx.TransportError as e:
last = str(e)
time.sleep(2 ** i)
raise RuntimeError(f"daily activity fetch failed: {last}") Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Error fetching cache settings: {e}
- DB not connected. This endpoint needs a database; set DATABA
- Please provide start_date and end_date
- Failed to update cost discount config: {e}
- Failed to update cost margin config: {e}
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/bc5c0fe14fac77d8.
Report an issue: GitHub.