{"record":{"id":"583c9f2bcfeb984f","repo":"unslothai/unsloth","slug":"request-failed-res-status","errorCode":null,"errorMessage":"Request failed (${res.status})","messagePattern":"Request failed \\((.+?)\\)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"studio/frontend/src/features/chat/api/prompts-api.ts","lineNumber":26,"sourceCode":"  name: string;\n  text: string;\n  createdAt: number;\n  updatedAt: number;\n}\n\nexport interface PromptListEntry {\n  id: string;\n  name: string;\n  items: string[];\n  createdAt: number;\n  updatedAt: number;\n}\n\nasync function parseJsonOrThrow<T>(res: Response): Promise<T> {\n  const body = await res.json().catch(() => null);\n  if (!res.ok) {\n    const detail = (body as { detail?: string } | null)?.detail;\n    throw new Error(detail ?? `Request failed (${res.status})`);\n  }\n  return body as T;\n}\n\nexport async function listPromptEntries(): Promise<PromptEntry[]> {\n  const res = await authFetch(\"/api/prompts/entries\");\n  const data = await parseJsonOrThrow<{ entries: PromptEntry[] }>(res);\n  return data.entries;\n}\n\nexport async function savePromptEntry(entry: PromptEntry): Promise<PromptEntry> {\n  const res = await authFetch(`/api/prompts/entries/${entry.id}`, {\n    method: \"PUT\",\n    headers: { \"Content-Type\": \"application/json\" },\n    body: JSON.stringify(entry),\n  });\n  return parseJsonOrThrow<PromptEntry>(res);\n}","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/frontend/src/features/chat/api/prompts-api.ts#L8-L44","documentation":"Fallback error from parseJsonOrThrow in prompts-api.ts: the response was non-ok AND the body either failed to parse as JSON or had no detail field. When detail exists the server's text is used instead; this generic 'Request failed (status)' is the last resort. It covers all prompt entry/list endpoints (/api/prompts/entries, /entries/bulk).","triggerScenarios":"GET/PUT/POST to /api/prompts/... returning an error with an empty or non-JSON body — e.g. a 500 with a bare HTML error page, a 502 from a dead backend, or 401 with no body.","commonSituations":"Prompts backend down (502/503 from gateway); reverse proxy returning HTML error pages that fail JSON parsing; auth middleware rejecting before the route body exists.","solutions":["Treat the bare status text as 'no structured error available' and check server/proxy logs for the real cause.","502/503: restart or verify the studio backend.","401/403: re-authenticate.","If you control the server, always include a JSON {detail} in error responses so clients get actionable text."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { return await parseJsonOrThrow<T>(res); }\ncatch (e) {\n  if (/Request failed \\((5\\d\\d|50[23])\\)/.test(String(e))) { await waitForBackend(); return retry(); }\n  throw e;\n}","preventionTips":["Make the backend always emit JSON {detail} on errors so the fallback never fires.","Distinguish fallback messages (no detail) from real detail text when routing errors.","Cache prompt lists locally to survive transient backend outages."],"tags":["prompts","http","fallback-message","api"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}