From 21bbba687f20fb00da867daa4ab13452fc9c6927 Mon Sep 17 00:00:00 2001 From: ryan-crabbe-berri Date: Sat, 6 Jun 2026 21:17:03 -0700 Subject: [PATCH] fix(ui): stop double-dispatching handleError from legacy query hooks The new global QueryCache.onError already routes every query error through handleError. The query fetch helpers in these hooks also called handleError inline, so each failure dispatched twice; today the second call is swallowed only by the 60s throttle in handleError, which is fragile if that throttle or handleError ever changes. Drop the inline call from the query paths and let the throw reach the global sink, which re-derives the same message. Mutation hooks are left as-is because there is no global MutationCache.onError; removing their inline handler would drop error reporting entirely. --- .../src/app/(dashboard)/hooks/keys/useKeys.ts | 3 +-- .../src/app/(dashboard)/hooks/projects/useProjectDetails.ts | 3 +-- .../src/app/(dashboard)/hooks/projects/useProjects.ts | 3 +-- .../src/app/(dashboard)/hooks/proxyConfig/useProxyConfig.ts | 1 - .../src/app/(dashboard)/hooks/teams/useTeams.ts | 4 +--- 5 files changed, 4 insertions(+), 10 deletions(-) diff --git a/ui/litellm-dashboard/src/app/(dashboard)/hooks/keys/useKeys.ts b/ui/litellm-dashboard/src/app/(dashboard)/hooks/keys/useKeys.ts index 701a9d30001..69308cad073 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/hooks/keys/useKeys.ts +++ b/ui/litellm-dashboard/src/app/(dashboard)/hooks/keys/useKeys.ts @@ -1,6 +1,6 @@ import { keepPreviousData, useQuery, UseQueryResult } from "@tanstack/react-query"; import { createQueryKeys } from "../common/queryKeysFactory"; -import { getProxyBaseUrl, getGlobalLitellmHeaderName, deriveErrorMessage, handleError } from "@/components/networking"; +import { getProxyBaseUrl, getGlobalLitellmHeaderName, deriveErrorMessage } from "@/components/networking"; import { KeyResponse } from "@/components/key_team_helpers/key_list"; import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized"; @@ -85,7 +85,6 @@ const keyListCall = async (accessToken: string, page: number, pageSize: number, if (!response.ok) { const errorData = await response.json(); const errorMessage = deriveErrorMessage(errorData); - handleError(errorMessage); throw new Error(errorMessage); } diff --git a/ui/litellm-dashboard/src/app/(dashboard)/hooks/projects/useProjectDetails.ts b/ui/litellm-dashboard/src/app/(dashboard)/hooks/projects/useProjectDetails.ts index 037baa18692..45bf7d5c4e0 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/hooks/projects/useProjectDetails.ts +++ b/ui/litellm-dashboard/src/app/(dashboard)/hooks/projects/useProjectDetails.ts @@ -1,5 +1,5 @@ import { useQuery, useQueryClient } from "@tanstack/react-query"; -import { getProxyBaseUrl, getGlobalLitellmHeaderName, deriveErrorMessage, handleError } from "@/components/networking"; +import { getProxyBaseUrl, getGlobalLitellmHeaderName, deriveErrorMessage } from "@/components/networking"; import { all_admin_roles } from "@/utils/roles"; import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized"; import { ProjectResponse, projectKeys } from "./useProjects"; @@ -21,7 +21,6 @@ const fetchProjectDetails = async (accessToken: string, projectId: string): Prom if (!response.ok) { const errorData = await response.json(); const errorMessage = deriveErrorMessage(errorData); - handleError(errorMessage); throw new Error(errorMessage); } diff --git a/ui/litellm-dashboard/src/app/(dashboard)/hooks/projects/useProjects.ts b/ui/litellm-dashboard/src/app/(dashboard)/hooks/projects/useProjects.ts index c240dbb0170..ecc123a0247 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/hooks/projects/useProjects.ts +++ b/ui/litellm-dashboard/src/app/(dashboard)/hooks/projects/useProjects.ts @@ -1,6 +1,6 @@ import { useQuery } from "@tanstack/react-query"; import { createQueryKeys } from "../common/queryKeysFactory"; -import { getProxyBaseUrl, getGlobalLitellmHeaderName, deriveErrorMessage, handleError } from "@/components/networking"; +import { getProxyBaseUrl, getGlobalLitellmHeaderName, deriveErrorMessage } from "@/components/networking"; import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized"; import { all_admin_roles, internalUserRoles } from "@/utils/roles"; @@ -61,7 +61,6 @@ const fetchProjects = async (accessToken: string): Promise => if (!response.ok) { const errorData = await response.json(); const errorMessage = deriveErrorMessage(errorData); - handleError(errorMessage); throw new Error(errorMessage); } diff --git a/ui/litellm-dashboard/src/app/(dashboard)/hooks/proxyConfig/useProxyConfig.ts b/ui/litellm-dashboard/src/app/(dashboard)/hooks/proxyConfig/useProxyConfig.ts index 485c7cc1f92..d055bb2d7ce 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/hooks/proxyConfig/useProxyConfig.ts +++ b/ui/litellm-dashboard/src/app/(dashboard)/hooks/proxyConfig/useProxyConfig.ts @@ -89,7 +89,6 @@ export const getProxyConfigCall = async (accessToken: string, configType: Config if (!response.ok) { const errorData = await response.json(); const errorMessage = deriveErrorMessage(errorData); - handleError(errorMessage); throw new Error(errorMessage); } diff --git a/ui/litellm-dashboard/src/app/(dashboard)/hooks/teams/useTeams.ts b/ui/litellm-dashboard/src/app/(dashboard)/hooks/teams/useTeams.ts index 81d2b84e9d9..521f1e8424c 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/hooks/teams/useTeams.ts +++ b/ui/litellm-dashboard/src/app/(dashboard)/hooks/teams/useTeams.ts @@ -4,7 +4,7 @@ import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized"; import { fetchTeams } from "@/app/(dashboard)/networking"; import { createQueryKeys } from "@/app/(dashboard)/hooks/common/queryKeysFactory"; import { teamInfoCall } from "@/components/networking"; -import { getProxyBaseUrl, getGlobalLitellmHeaderName, deriveErrorMessage, handleError } from "@/components/networking"; +import { getProxyBaseUrl, getGlobalLitellmHeaderName, deriveErrorMessage } from "@/components/networking"; export interface TeamsResponse { teams: Team[]; @@ -72,7 +72,6 @@ export const teamListCall = async ( if (!response.ok) { const errorData = await response.json(); const errorMessage = deriveErrorMessage(errorData); - handleError(errorMessage); throw new Error(errorMessage); } @@ -220,7 +219,6 @@ const deletedTeamListCall = async ( if (!response.ok) { const errorData = await response.json(); const errorMessage = deriveErrorMessage(errorData); - handleError(errorMessage); throw new Error(errorMessage); }