{"record":{"id":"983698ca1452377d","repo":"pinpoint-apm/pinpoint","slug":"request-failed-with-status-response-status-an","errorCode":null,"errorMessage":"Request failed with status ${response.status}. An error occurred while fetching the data.","messagePattern":"Request failed with status (.+?)\\. An error occurred while fetching the data\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web-frontend/src/main/v3/packages/ui/src/hooks/api/reactQueryHelper.tsx","lineNumber":44,"sourceCode":"  }\n}\n\nfunction isServerErrorResponse(body: unknown): body is ErrorResponse {\n  const o = body as Record<string, unknown>;\n  return (\n    o != null &&\n    typeof o === 'object' &&\n    typeof o.status === 'number' &&\n    (typeof o.detail === 'string' || typeof o.title === 'string')\n  );\n}\n\nexport async function parseResponseError(response: Response): Promise<never> {\n  let body: unknown;\n  try {\n    body = await response.json();\n  } catch {\n    throw new Error(\n      `Request failed with status ${response.status}. An error occurred while fetching the data.`,\n    );\n  }\n\n  if (isServerErrorResponse(body)) {\n    const serverError = body;\n    const err = new Error(\n      serverError.detail || serverError.title || 'An error occurred while fetching the data.',\n    ) as Error & ErrorResponse;\n    Object.assign(err, serverError);\n    err.message = serverError.detail || serverError.title || err.message;\n    throw err;\n  }\n\n  const detail =\n    typeof (body as Record<string, unknown>)?.detail === 'string'\n      ? (body as Record<string, unknown>).detail\n      : typeof (body as Record<string, unknown>)?.message === 'string'","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/web-frontend/src/main/v3/packages/ui/src/hooks/api/reactQueryHelper.tsx#L26-L62","documentation":"In Pinpoint's web-frontend reactQueryHelper, parseResponseError is called for non-OK fetch responses and first attempts response.json(). If the response body is not valid JSON (json() throws), the helper throws a generic Error including the HTTP status: 'Request failed with status <status>. An error occurred while fetching the data.' This is the fallback path when the server did not return a parseable JSON error body.","triggerScenarios":"A fetch wrapper calls parseResponseError on a non-2xx response whose body is empty, HTML (e.g. a proxy/gateway error page), plain text, or otherwise unparseable JSON.","commonSituations":"Backend down and a load balancer returns an HTML 502/503 page; session expired and server returns an HTML login redirect; gateway truncates the body; wrong Content-Type causes json() to fail even when a body exists.","solutions":["Check the backend/Pinpoint web server is running and reachable — HTML gateway error pages are the usual cause.","Inspect response.status: 401/403 means re-authenticate, 5xx means server-side failure.","Check proxies/reverse proxies (nginx, gateway) are not intercepting the request with non-JSON error pages.","Server-side: ensure error handlers return a JSON body so the isServerErrorResponse branch is used instead.","Client-side: wrap calls to react-query hooks in try/catch and surface error.message plus response status to users."],"exampleFix":"// before\nif (!res.ok) return parseResponseError(res); // opaque error when body isn't JSON\n// after\nif (!res.ok) {\n  const ct = res.headers.get('content-type') || '';\n  if (!ct.includes('application/json')) {\n    console.error('Non-JSON error response', res.status, await res.text());\n  }\n  return parseResponseError(res);\n}","handlingStrategy":"try-catch","validationCode":"if (!response.ok && !(response.headers.get('content-type') || '').includes('application/json')) {\n  throw new Error(`Non-JSON error response (${response.status}); server or proxy likely misconfigured`);\n}","typeGuard":"const isJsonResponse = async (res: Response): Promise<boolean> =>\n  (res.headers.get('content-type') || '').includes('application/json') &&\n  (await res.clone().text()).trim().startsWith('{');","tryCatchPattern":"try {\n  const data = await queryFn();\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Request failed with status')) {\n    const status = Number(e.message.match(/status (\\d+)/)?.[1] ?? 0);\n    if (status === 401 || status === 403) redirectToLogin();\n    else if (status >= 500) showError('Server unavailable, please retry later');\n    else showError(e.message);\n  } else throw e;\n}","preventionTips":["Monitor backend health; HTML 502/503 proxy pages are the usual source of unparseable bodies.","Handle 401/403 centrally (e.g. auth redirect) before generic error parsing.","Ensure server error handlers always emit JSON with a proper Content-Type.","Log response.text() for non-JSON error responses to aid debugging.","Add react-query onError handlers that distinguish network/auth/server failures."],"tags":["http","fetch","react-query","json","frontend"],"backgroundTag":"invalid-json-response","analyzedSha":"744c3d3075e595656abb1ae331ad2c0e4c9eb996","analyzedAt":"2026-09-07T18:48:45.289Z","contentChangedAt":"2026-09-07T18:48:45.289Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}