From 28e58a5a5c297938b10fee4561203da003caaece Mon Sep 17 00:00:00 2001 From: Thomas Camlong Date: Fri, 14 Aug 2026 22:37:28 +0200 Subject: [PATCH] fix: expose assistant provider errors --- .../chat/assistant-stream-error.spec.ts | 16 ++++++++++++++++ .../api/assistant/chat/assistant-stream-error.ts | 12 ++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/apps/nextjs/src/app/api/assistant/chat/assistant-stream-error.spec.ts b/apps/nextjs/src/app/api/assistant/chat/assistant-stream-error.spec.ts index 27b499431..b024055e7 100644 --- a/apps/nextjs/src/app/api/assistant/chat/assistant-stream-error.spec.ts +++ b/apps/nextjs/src/app/api/assistant/chat/assistant-stream-error.spec.ts @@ -54,4 +54,20 @@ describe("assistant stream errors", () => { ])("prefers actionable status %s over a generic input-stream phrase", (statusCode, expected) => { expect(getAssistantStreamErrorMessage({ statusCode, responseBody: "Error in input stream" })).toBe(expected); }); + + test("returns the provider error instead of replacing it with a generic message", () => { + expect(getAssistantStreamErrorMessage(new Error("Provider connection failed: certificate expired"))).toBe( + "Provider connection failed: certificate expired", + ); + }); + + test("returns nested provider error details", () => { + expect( + getAssistantStreamErrorMessage({ + error: { + message: "No endpoints found for the selected model", + }, + }), + ).toBe("No endpoints found for the selected model"); + }); }); diff --git a/apps/nextjs/src/app/api/assistant/chat/assistant-stream-error.ts b/apps/nextjs/src/app/api/assistant/chat/assistant-stream-error.ts index 6bb1e2a8a..2a3b72f17 100644 --- a/apps/nextjs/src/app/api/assistant/chat/assistant-stream-error.ts +++ b/apps/nextjs/src/app/api/assistant/chat/assistant-stream-error.ts @@ -14,15 +14,19 @@ const getStatusCode = (error: unknown): number | undefined => { return getStatusCode(record.cause) ?? getStatusCode(record.response); }; -const getErrorMessage = (error: unknown): string => { +const getErrorMessage = (error: unknown, seen = new Set()): string => { if (error instanceof Error) { - return `${error.message} ${getErrorMessage(error.cause)}`.trim(); + if (seen.has(error)) return ""; + seen.add(error); + return `${error.message} ${getErrorMessage(error.cause, seen)}`.trim(); } const record = asRecord(error); if (!record) return typeof error === "string" ? error : ""; + if (seen.has(record)) return ""; + seen.add(record); const responseBody = typeof record.responseBody === "string" ? record.responseBody : ""; const message = typeof record.message === "string" ? record.message : ""; - return `${message} ${responseBody} ${getErrorMessage(record.cause)}`.trim(); + return `${message} ${responseBody} ${getErrorMessage(record.error, seen)} ${getErrorMessage(record.cause, seen)}`.trim(); }; export const getAssistantStreamErrorMessage = (error: unknown) => { @@ -65,5 +69,5 @@ export const getAssistantStreamErrorMessage = (error: unknown) => { return "The model provider interrupted the streamed response before the assistant could finish. Try again."; } - return "The model endpoint stopped the response. Try again, or ask an administrator to verify its URL, model, and credentials."; + return message || "The model endpoint stopped without providing an error message."; };