2026-06-01 23:05:38 -07:00
|
|
|
/**
|
|
|
|
|
* Extract a human-readable message from a backend error response.
|
|
|
|
|
*
|
|
|
|
|
* The generated API client returns `{ error }` on failure (it does not throw),
|
2026-06-12 14:55:30 +05:30
|
|
|
* and FastAPI shapes that error as `{ detail: string }`, `{ detail:
|
|
|
|
|
* [{ msg, loc, ... }] }`, or backend validation arrays like `{ detail:
|
|
|
|
|
* [{ model, message }] }`. This normalizes those to a single string so it can
|
|
|
|
|
* be rendered or thrown directly.
|
2026-06-01 23:05:38 -07:00
|
|
|
*/
|
|
|
|
|
export function detailFromError(err: unknown, fallback = "Request failed"): string {
|
|
|
|
|
if (typeof err === "string") return err;
|
|
|
|
|
const e = err as { detail?: unknown };
|
|
|
|
|
if (typeof e?.detail === "string") return e.detail;
|
|
|
|
|
if (Array.isArray(e?.detail) && e.detail.length > 0) {
|
2026-06-12 14:55:30 +05:30
|
|
|
const messages = e.detail
|
|
|
|
|
.map((item) => {
|
|
|
|
|
if (typeof item === "string") return item;
|
|
|
|
|
if (!item || typeof item !== "object") return null;
|
|
|
|
|
const detail = item as { message?: unknown; msg?: unknown; model?: unknown };
|
|
|
|
|
const message = typeof detail.message === "string"
|
|
|
|
|
? detail.message
|
|
|
|
|
: typeof detail.msg === "string"
|
|
|
|
|
? detail.msg
|
|
|
|
|
: null;
|
|
|
|
|
if (!message) return null;
|
|
|
|
|
return typeof detail.model === "string" && detail.model
|
|
|
|
|
? `${detail.model}: ${message}`
|
|
|
|
|
: message;
|
|
|
|
|
})
|
|
|
|
|
.filter((message): message is string => Boolean(message));
|
|
|
|
|
if (messages.length > 0) return messages.join("\n");
|
2026-06-01 23:05:38 -07:00
|
|
|
}
|
|
|
|
|
return fallback;
|
|
|
|
|
}
|