diff --git a/ui/litellm-dashboard/src/components/chat_ui/ResponseMetrics.test.tsx b/ui/litellm-dashboard/src/components/chat_ui/ResponseMetrics.test.tsx
index f31e1839739..4ba6d8d50b4 100644
--- a/ui/litellm-dashboard/src/components/chat_ui/ResponseMetrics.test.tsx
+++ b/ui/litellm-dashboard/src/components/chat_ui/ResponseMetrics.test.tsx
@@ -51,4 +51,23 @@ describe("ResponseMetrics prompt cache chips", () => {
expect(screen.queryByText(/Response Cache/)).not.toBeInTheDocument();
});
+
+ it("does not render the Cost chip when a persisted cost is null", () => {
+ render();
+
+ expect(screen.queryByText(/Cost:/)).not.toBeInTheDocument();
+ expect(screen.getByText("In: 1")).toBeInTheDocument();
+ });
+
+ it("does not render the Cost chip for NaN", () => {
+ render();
+
+ expect(screen.queryByText(/Cost:/)).not.toBeInTheDocument();
+ });
+
+ it("renders the Cost chip for a finite cost", () => {
+ render();
+
+ expect(screen.getByText("Cost: $0.000063")).toBeInTheDocument();
+ });
});
diff --git a/ui/litellm-dashboard/src/components/chat_ui/ResponseMetrics.tsx b/ui/litellm-dashboard/src/components/chat_ui/ResponseMetrics.tsx
index ec62d0618d7..bb7debc7aee 100644
--- a/ui/litellm-dashboard/src/components/chat_ui/ResponseMetrics.tsx
+++ b/ui/litellm-dashboard/src/components/chat_ui/ResponseMetrics.tsx
@@ -159,7 +159,7 @@ const ResponseMetrics: React.FC = ({ timeToFirstToken, tot
/>
)}
- {usage?.cost !== undefined && (
+ {typeof usage?.cost === "number" && Number.isFinite(usage.cost) && (
{
expect(usageData).not.toHaveProperty("cacheReadTokens");
expect(usageData).not.toHaveProperty("cacheCreationTokens");
});
+
+ it("omits cost when the provider reports a non-numeric value", async () => {
+ const usageData = await captureUsage({ cost: "not-a-number" });
+
+ expect(usageData).toEqual(expect.not.objectContaining({ cost: expect.anything() }));
+ });
});
describe("chat_completion response cache", () => {
diff --git a/ui/litellm-dashboard/src/components/llm_calls/chat_completion.tsx b/ui/litellm-dashboard/src/components/llm_calls/chat_completion.tsx
index cd0852bc06e..b813a35f687 100644
--- a/ui/litellm-dashboard/src/components/llm_calls/chat_completion.tsx
+++ b/ui/litellm-dashboard/src/components/llm_calls/chat_completion.tsx
@@ -245,7 +245,10 @@ export async function makeOpenAIChatCompletionRequest(
// Extract cost from usage object if available
if (chunkWithUsage.usage.cost !== undefined && chunkWithUsage.usage.cost !== null) {
- usageData.cost = parseFloat(chunkWithUsage.usage.cost);
+ const parsedCost = parseFloat(chunkWithUsage.usage.cost);
+ if (Number.isFinite(parsedCost)) {
+ usageData.cost = parsedCost;
+ }
}
onUsageData(usageData);
diff --git a/ui/litellm-dashboard/src/components/llm_calls/responses_api.test.tsx b/ui/litellm-dashboard/src/components/llm_calls/responses_api.test.tsx
index 0b94c093acd..7b13f0ac2e3 100644
--- a/ui/litellm-dashboard/src/components/llm_calls/responses_api.test.tsx
+++ b/ui/litellm-dashboard/src/components/llm_calls/responses_api.test.tsx
@@ -231,6 +231,35 @@ describe("responses_api", () => {
expect(onUsageData).toHaveBeenCalledWith(expect.not.objectContaining({ cost: expect.anything() }), "");
});
+ it("should omit cost when the proxy reports a non-numeric cost", async () => {
+ async function* streamWithNonNumericCost() {
+ yield {
+ type: "response.completed",
+ response: {
+ id: "resp_non_numeric_cost",
+ usage: { output_tokens: 12, input_tokens: 12, total_tokens: 24, cost: "not-a-number" },
+ },
+ };
+ }
+ mockResponsesCreate.mockResolvedValueOnce(streamWithNonNumericCost());
+
+ const onUsageData = vi.fn();
+
+ await makeOpenAIResponsesRequest(
+ messages,
+ mockUpdateTextUI,
+ "gpt-4",
+ "test-token",
+ undefined,
+ undefined,
+ undefined,
+ undefined,
+ onUsageData,
+ );
+
+ expect(onUsageData).toHaveBeenCalledWith(expect.not.objectContaining({ cost: expect.anything() }), "");
+ });
+
it("should replay MCP output items as events for a non-streaming response", async () => {
mockResponsesCreate.mockReturnValueOnce(
nonStreamingResponse({
diff --git a/ui/litellm-dashboard/src/components/llm_calls/responses_api.tsx b/ui/litellm-dashboard/src/components/llm_calls/responses_api.tsx
index 7ab76488504..63085a81b94 100644
--- a/ui/litellm-dashboard/src/components/llm_calls/responses_api.tsx
+++ b/ui/litellm-dashboard/src/components/llm_calls/responses_api.tsx
@@ -312,7 +312,10 @@ export async function makeOpenAIResponsesRequest(
}
if (usage.cost !== undefined && usage.cost !== null) {
- usageData.cost = Number(usage.cost);
+ const parsedCost = Number(usage.cost);
+ if (Number.isFinite(parsedCost)) {
+ usageData.cost = parsedCost;
+ }
}
onUsageData(usageData, mcpToolUsed);