Skip to content

bug(ui): PriceDataReload polls admin APIs every 30s with expired virtual key, spamming server with ProxyException auth errors #24349

@xykong

Description

@xykong

Describe the bug

The PriceDataReload component (ui/litellm-dashboard/src/components/price_data_reload.tsx) polls two admin endpoints every 30 seconds via setInterval:

  • GET /schedule/model_cost_map_reload/status
  • GET /model/cost_map/source

It authenticates using accessToken = decoded?.key extracted from the JWT cookie. When a user's virtual key expires, the JWT cookie itself may still be valid (the user stays logged in), but every polling request hits user_api_key_auth which raises:

ProxyException: Authentication Error - Expired Key

This produces continuous HTTP 400 errors in the server logs every 30 seconds, indefinitely, until the user manually refreshes the browser — even though the page appears to function normally.

Reproduction

  1. Open the Admin UI → Models & EndpointsPrice Data Reload tab
  2. Leave the browser tab open with an expired virtual key
  3. Observe repeated LiteLLM Proxy:ERROR auth_exception_handler.py:78 - user_api_key_auth(): Exception occured in pod logs every ~30 seconds

Expected behavior

When the polling requests receive HTTP 400/401 (auth failure), the interval should stop. The UI should show a message prompting the user to re-login rather than silently continuing to spam the server.

Logs

06:21:45 - LiteLLM Proxy:ERROR: auth_exception_handler.py:78 - litellm.proxy.proxy_server.user_api_key_auth(): Exception occured -
Requester IP Address: <internal>
litellm.proxy._types.ProxyException
INFO: <ip> - "GET /schedule/model_cost_map_reload/status HTTP/1.1" 400 Bad Request

06:50:39 - LiteLLM Proxy:ERROR: auth_exception_handler.py:78 - litellm.proxy.proxy_server.user_api_key_auth(): Exception occured -
Requester IP Address: <internal>
INFO: <ip> - "GET /model/cost_map/source HTTP/1.1" 400 Bad Request
[repeating every ~30s]

Root cause

In price_data_reload.tsx, the useEffect starts an interval but never checks whether API calls return auth errors:

const interval = setInterval(() => {
  fetchReloadStatus();   // throws on HTTP 400, but catch block doesn't stop the interval
  fetchSourceInfo();
}, 30000);

The catch blocks log the error and set default state but do not clear the interval.

Fix

A fix has been submitted in PR #XXXX. Summary:

  • Extract isAuthError() helper to detect HTTP 400/401 responses
  • Wrap fetchReloadStatus / fetchSourceInfo with useCallback
  • On auth error, call stopPolling() which clears the interval and sets pollingDisabled = true
  • Show an <Alert> banner when polling is paused, prompting re-login
  • useEffect depends on pollingDisabled so it restarts correctly after fresh login

LiteLLM Version

Reproducible on current main (c89496f).

Environment

  • Deployment: Kubernetes (LiteLLM Proxy)
  • UI accessed via Admin Dashboard
  • Virtual key with expiry set

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions