From d2b7996170c16767b1f08d9327fd2f96c9422d78 Mon Sep 17 00:00:00 2001 From: Tin Chi Lo Date: Fri, 10 Jul 2026 00:57:31 -0700 Subject: [PATCH] test(ui): pin deriveErrorMessage against the ProxyException wire shape Both automated reviewers assumed the semantic filter 400 reaches the browser as FastAPI's flat detail dict and would render as raw JSON in the test panel banner. The proxy converts a pre-call hook HTTPException into a ProxyException that serializes as {"error": {"message": ...}}, which deriveErrorMessage unpacks first; pin that contract with direct tests --- .../src/lib/http/client.test.ts | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/ui/litellm-dashboard/src/lib/http/client.test.ts b/ui/litellm-dashboard/src/lib/http/client.test.ts index 6d50f99feca..e0b5a73d11a 100644 --- a/ui/litellm-dashboard/src/lib/http/client.test.ts +++ b/ui/litellm-dashboard/src/lib/http/client.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, vi } from "vitest"; -import { createApiClient, ApiError } from "./client"; +import { createApiClient, ApiError, deriveErrorMessage } from "./client"; const okResponse = (data: unknown): Response => ({ ok: true, status: 200, text: async () => JSON.stringify(data) }) as unknown as Response; @@ -101,3 +101,22 @@ describe("createApiClient", () => { } }); }); + +describe("deriveErrorMessage", () => { + it("extracts error.message from a ProxyException body, the shape the proxy emits for a pre-call hook HTTPException", () => { + const actionable = + "MCP semantic tool filtering could not run: embedding model 'text-embedding-3-small' exceeded its context window while embedding the user query. The request was blocked instead of silently passing all tools through. Switch to an embedding model with a larger context window, or disable semantic tool filtering."; + const wireBody = { + error: { message: actionable, type: "None", param: "None", code: "400" }, + }; + expect(deriveErrorMessage(wireBody)).toBe(actionable); + }); + + it("returns error directly when it is a plain string", () => { + expect(deriveErrorMessage({ error: "flat error text" })).toBe("flat error text"); + }); + + it("falls back to a string detail field", () => { + expect(deriveErrorMessage({ detail: "detail text" })).toBe("detail text"); + }); +});