diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cd6f23b6..05311a6e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,30 @@ # Changelog +## [1.4.5] — 2026-05-09 + +### Fixed — Settings · KI + +- **"Verbindung testen" no longer crashes the page when the key is + bad.** The endpoint mapped every upstream error to HTTP 502, which + Cloudflare intercepts and replaces with its own HTML error page. + `await res.json()` in the browser then crashed with `Unexpected + token '<', " { const response = await POST(emptyRequest() as never); const body = (await response.json()) as ApiErrorEnvelope; - expect(response.status).toBe(502); + // v1.4.5: credential failures map to 422 (not 502) so Cloudflare + // doesn't replace our JSON body with its HTML error page — that + // rewrite was the root cause of the "Unexpected token '<'…" client + // crash Marc hit when typing a bad OpenAI key. + expect(response.status).toBe(422); expect(body.error ?? "").not.toMatch(/sk-/); expect(body.error ?? "").not.toMatch(/api\.openai\.com/); expect(body.error ?? "").not.toMatch(/invalid api key/i); @@ -106,7 +110,10 @@ describe("POST /api/ai/test — provider error leak guard", () => { Object.assign(new Error("429 from openai"), { httpStatus: 429 as const }), ); const response = await POST(emptyRequest() as never); - expect(response.status).toBe(502); + // v1.4.5: rate-limit passes through as 429 (was 502 in v1.4.4) so + // the React Query mutation can read the JSON body instead of + // tripping over Cloudflare's HTML 502. + expect(response.status).toBe(429); expect(((await response.json()) as ApiErrorEnvelope).error).toBe( "Provider rate-limited the request", ); diff --git a/src/app/api/ai/test/route.ts b/src/app/api/ai/test/route.ts index ce98160e9..77cf7f4a5 100644 --- a/src/app/api/ai/test/route.ts +++ b/src/app/api/ai/test/route.ts @@ -91,15 +91,28 @@ export const POST = apiHandler(async (request: NextRequest) => { ai_test_provider: provider.type, }, }); + // Map upstream status to a *client-side* status code that won't be + // rewritten by Cloudflare. 5xx from origin causes Cloudflare to swap + // the body for its own HTML error page — `await res.json()` in the + // browser then crashes with `Unexpected token '<', "= 500 - ? "Provider returned a server error" - : "Provider connection failed"; - return apiError(safeMessage, 502); + let outboundStatus: number; + let safeMessage: string; + if (status === 401 || status === 403) { + outboundStatus = 422; + safeMessage = "Provider rejected the credentials"; + } else if (status === 429) { + outboundStatus = 429; + safeMessage = "Provider rate-limited the request"; + } else if (status >= 500) { + outboundStatus = 502; + safeMessage = "Provider returned a server error"; + } else { + outboundStatus = 422; + safeMessage = "Provider connection failed"; + } + return apiError(safeMessage, outboundStatus); } }); diff --git a/src/app/page.tsx b/src/app/page.tsx index 66e1e0fdb..b50b12d28 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -881,21 +881,22 @@ export default function DashboardPage() { * touch. */}