From cac6dfbe45e080797b9f6d03dc447eeb932bdba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=9E=97?= <2281216234@qq.com> Date: Sun, 30 Aug 2026 18:16:15 +0800 Subject: [PATCH] fix(explorer): surface server error detail in graph loading failures (#1260) The nodes/edges fetch loops were throwing away the response body whenever the request returned a non-OK status. Because of that, errors like a `503` caused by a missing `SEMANTICA_API_KEY` only showed up as: `Fetch failed: 503` even though the backend was already returning a more useful message in the response `detail`. This change reads the JSON error body and includes `detail` in the thrown error when it's a string, so `GraphLoadingOverlay` can show the actual backend error to the user. Closes #1256 --- .../workspaces/GraphWorkspace/useLoadGraph.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/explorer/src/workspaces/GraphWorkspace/useLoadGraph.ts b/explorer/src/workspaces/GraphWorkspace/useLoadGraph.ts index f23c563a..cc39df99 100644 --- a/explorer/src/workspaces/GraphWorkspace/useLoadGraph.ts +++ b/explorer/src/workspaces/GraphWorkspace/useLoadGraph.ts @@ -318,6 +318,20 @@ interface EdgeListResponse { const PAGE_LIMIT = 1000; +/** Surface the server's `detail` message (e.g. auth/setup guidance) on non-OK responses. */ +async function fetchErrorDetail(response: Response): Promise { + try { + const body: unknown = await response.json(); + const detail = (body as { detail?: unknown } | null)?.detail; + if (typeof detail === "string" && detail.trim()) { + return ` — ${detail.trim()}`; + } + } catch { + // Non-JSON or unreadable body: fall back to the status-only message. + } + return ""; +} + async function fetchAllNodes( signal: AbortSignal, onProgress?: (progress: GraphLoadProgress) => void, @@ -335,7 +349,7 @@ async function fetchAllNodes( const response = await fetch(url.toString(), { signal }); if (!response.ok) { - throw new Error(`Fetch failed: ${response.status}`); + throw new Error(`Fetch failed: ${response.status}${await fetchErrorDetail(response)}`); } const data: NodeListResponse = await response.json(); @@ -390,7 +404,7 @@ async function fetchAllEdges( const response = await fetch(url.toString(), { signal }); if (!response.ok) { - throw new Error(`Fetch failed: ${response.status}`); + throw new Error(`Fetch failed: ${response.status}${await fetchErrorDetail(response)}`); } const data: EdgeListResponse = await response.json();