mirror of
https://github.com/anand34577/ferrum.git
synced 2026-09-20 17:43:21 +00:00
Fix icon-only error toasts: never throw ApiError with an empty message
Error responses that aren't the backend's {"error": ...} JSON shape
(reverse-proxy 502/504 HTML pages, non-JSON bodies) fell back to
res.statusText, which is an empty string over HTTP/2 — so every
toast.error(err.message) call rendered a toast with an icon and no text,
in light and dark themes alike. Fall through empty/non-string values to
a generic "Request failed (HTTP <status>)" message instead. Same fix in
the UploadTemplateDialog's raw-fetch path and in the web-demo copies.
This commit is contained in:
@@ -17,7 +17,13 @@ import { api, ApiError, type ClusterResource, type Storage } from "@/lib/api"
|
||||
async function uploadFile(path: string, form: FormData): Promise<{ upid: string }> {
|
||||
const res = await fetch(`/api/v1${path}`, { method: "POST", body: form, credentials: "include" })
|
||||
const data = await res.json().catch(() => undefined)
|
||||
if (!res.ok) throw new ApiError(res.status, data?.error ?? res.statusText, data?.code)
|
||||
if (!res.ok) {
|
||||
throw new ApiError(
|
||||
res.status,
|
||||
(typeof data?.error === "string" && data.error) || res.statusText || `Request failed (HTTP ${res.status})`,
|
||||
data?.code,
|
||||
)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,15 @@ async function request<T>(path: string, init?: RequestInit): Promise<T> {
|
||||
if (data?.code) {
|
||||
for (const handler of errorCodeHandlers) handler(data.code)
|
||||
}
|
||||
throw new ApiError(res.status, data?.error ?? res.statusText, data?.code)
|
||||
// `||` (not ??) so empty values fall through: statusText is "" over
|
||||
// HTTP/2, and an empty message renders as an icon-only toast. The typeof
|
||||
// guard keeps a non-string `error` (e.g. an OpenAI-style object from a
|
||||
// proxy) from becoming "[object Object]".
|
||||
throw new ApiError(
|
||||
res.status,
|
||||
(typeof data?.error === "string" && data.error) || res.statusText || `Request failed (HTTP ${res.status})`,
|
||||
data?.code,
|
||||
)
|
||||
}
|
||||
return data as T
|
||||
}
|
||||
|
||||
@@ -17,7 +17,13 @@ import { api, ApiError, type ClusterResource, type Storage } from "@/lib/api"
|
||||
async function uploadFile(path: string, form: FormData): Promise<{ upid: string }> {
|
||||
const res = await fetch(`/api/v1${path}`, { method: "POST", body: form, credentials: "include" })
|
||||
const data = await res.json().catch(() => undefined)
|
||||
if (!res.ok) throw new ApiError(res.status, data?.error ?? res.statusText, data?.code)
|
||||
if (!res.ok) {
|
||||
throw new ApiError(
|
||||
res.status,
|
||||
(typeof data?.error === "string" && data.error) || res.statusText || `Request failed (HTTP ${res.status})`,
|
||||
data?.code,
|
||||
)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
|
||||
+9
-1
@@ -63,7 +63,15 @@ async function request<T>(path: string, init?: RequestInit): Promise<T> {
|
||||
if (data?.code) {
|
||||
for (const handler of errorCodeHandlers) handler(data.code)
|
||||
}
|
||||
throw new ApiError(res.status, data?.error ?? res.statusText, data?.code)
|
||||
// `||` (not ??) so empty values fall through: statusText is "" over
|
||||
// HTTP/2, and an empty message renders as an icon-only toast. The typeof
|
||||
// guard keeps a non-string `error` (e.g. an OpenAI-style object from a
|
||||
// proxy) from becoming "[object Object]".
|
||||
throw new ApiError(
|
||||
res.status,
|
||||
(typeof data?.error === "string" && data.error) || res.statusText || `Request failed (HTTP ${res.status})`,
|
||||
data?.code,
|
||||
)
|
||||
}
|
||||
return data as T
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user