diff --git a/client/src/lib/api.ts b/client/src/lib/api.ts index 73c196c..4204ef1 100644 --- a/client/src/lib/api.ts +++ b/client/src/lib/api.ts @@ -21,7 +21,18 @@ async function request(method: string, url: string, body?: unknown): Promise< } const contentType = response.headers.get('content-type') ?? '' - return contentType.includes('application/json') ? ((await response.json()) as T) : (undefined as T) + if (contentType.includes('application/json')) { + return (await response.json()) as T + } + + // A non-JSON 2xx on an /api call is almost always the SPA fallback (index.html) — i.e. the route + // doesn't exist on the backend that's running (a stale build). Fail loudly so callers surface it, + // instead of returning undefined and letting the page crash on `.map`/`.length`. + if (url.startsWith('/api') && contentType.includes('text/html')) { + throw new Error(`Unexpected HTML from ${url}. The API is likely running an older build — restart the server.`) + } + + return undefined as T } export const api = { diff --git a/client/src/pages/PipelinePage.tsx b/client/src/pages/PipelinePage.tsx index 7c03ecc..a4007e2 100644 --- a/client/src/pages/PipelinePage.tsx +++ b/client/src/pages/PipelinePage.tsx @@ -97,8 +97,8 @@ export function PipelinePage() { api.get(`/api/orgboard/change-requests?organizationId=${organizationId}`), api.get(`/api/orgboard/divisions?organizationId=${organizationId}`).catch(() => []), ]) - setRequests(list) - setDivisions(divs) + setRequests(Array.isArray(list) ? list : []) + setDivisions(Array.isArray(divs) ? divs : []) } catch (err) { toast.error((err as Error).message) }