{"record":{"id":"78580596c0ec18ce","repo":"decolua/9router","slug":"request-failed-response-status","errorCode":null,"errorMessage":"Request failed (${response.status})","messagePattern":"Request failed \\((.+?)\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/app/(dashboard)/dashboard/basic-chat/BasicChatPageClient.js","lineNumber":655,"sourceCode":"\n    try {\n      const response = await fetch(\"/api/dashboard/chat/completions\", {\n        method: \"POST\",\n        headers: {\n          \"Content-Type\": \"application/json\",\n          Accept: \"text/event-stream\",\n        },\n        body: JSON.stringify({\n          model: model.requestModel || model.id,\n          messages: requestMessages,\n          stream: true,\n        }),\n        signal: abortRef.current.signal,\n      });\n\n      if (!response.ok) {\n        const errorData = await response.json().catch(() => ({}));\n        throw new Error(textValue(errorData.error || errorData.message || `Request failed (${response.status})`));\n      }\n\n      const reader = response.body?.getReader();\n      if (!reader) {\n        const data = await response.json().catch(() => ({}));\n        const fallbackText = textValue(data?.choices?.[0]?.message?.content || data?.output_text || data?.error || data?.message || \"\");\n        updateSession(sessionId, (currentSession) => ({\n          ...currentSession,\n          messages: currentSession.messages.map((message) => (message.id === assistantMessageId ? { ...message, content: fallbackText, status: \"done\" } : message)),\n          updatedAt: new Date().toISOString(),\n        }));\n        return;\n      }\n\n      const decoder = new TextDecoder();\n      let buffer = \"\";\n      let assistantText = \"\";\n","sourceCodeStart":637,"sourceCodeEnd":673,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/app/(dashboard)/dashboard/basic-chat/BasicChatPageClient.js#L637-L673","documentation":"The dashboard basic-chat client calls its own /api chat endpoint and, when response.ok is false, parses the JSON body for `error` or `message`; if neither exists it falls back to a generic \"Request failed (<status>)\". So this exact message means the server returned an error HTTP status but a body without a readable error field (or the body wasn't JSON).","triggerScenarios":"POSTing a chat completion from BasicChatPageClient and receiving 4xx/5xx whose body lacks `error`/`message` — gateway 502 HTML page, 401 with empty body, or proxy-generated error pages.","commonSituations":"Server not running or crashed mid-deploy (502/504 from reverse proxy); session expired (401) with non-JSON body; upstream provider key missing so the API returned a bare status; rate-limit 429 with empty body.","solutions":["Check the browser Network tab for the actual status code and raw response body to find the real cause.","401 → re-login to the dashboard (JWT session expired).","5xx → check the server logs at the corresponding /api/v1 handler for the upstream failure.","Verify the gateway/upstream provider credentials and that the server is running at the expected PORT."],"exampleFix":"// before\nconst errorData = await response.json().catch(() => ({}));\nthrow new Error(textValue(errorData.error || ...));\n// after — also surface status + raw text for debugging\nconst raw = await response.text();\nlet errorData = {}; try { errorData = JSON.parse(raw); } catch {}\nthrow new Error(errorData.error || raw.slice(0, 200) || `Request failed (${response.status})`);","handlingStrategy":"try-catch","validationCode":"// client-side pre-flight: ensure a session exists and the API is up\nconst health = await fetch(\"/api/health\", { signal }).catch(() => null);\nif (!health?.ok) throw new Error(\"Gateway unavailable before chat request\");\n","typeGuard":"const hasApiErrorBody = (d) => d && (typeof d.error === \"string\" || typeof d.message === \"string\");","tryCatchPattern":"if (!response.ok) {\n  const raw = await response.text();\n  let body = {}; try { body = JSON.parse(raw); } catch {}\n  const msg = body.error || body.message || (response.status === 401 ? \"Session expired — please log in again\" : `Request failed (${response.status}): ${raw.slice(0, 200)}`);\n  showError(msg);\n  return;\n}","preventionTips":["Handle 401 by redirecting to login before showing a generic error.","Show the HTTP status to users and log the raw body for support.","Add abort/timeout handling so hung requests surface a clear message.","Keep dashboard session cookies fresh; warn before JWT expiry."],"tags":["http-error","frontend","fetch","dashboard"],"backgroundTag":"http-request-failed","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}