{"record":{"id":"b04096eb7611a2d2","repo":"unslothai/unsloth","slug":"request-failed-status-b04096","errorCode":null,"errorMessage":"Request failed (${status})","messagePattern":"Request failed \\((.+?)\\)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"studio/frontend/src/features/chat/api/providers-api.ts","lineNumber":82,"sourceCode":"  message: string;\n  models_count?: number | null;\n}\n\nfunction parseErrorText(status: number, body: unknown): string {\n  if (body && typeof body === \"object\") {\n    const detail = (body as { detail?: unknown }).detail;\n    const formatted = formatFastApiDetail(detail);\n    if (formatted) return formatted;\n    const message = (body as { message?: unknown }).message;\n    if (typeof message === \"string\" && message) return message;\n  }\n  return `Request failed (${status})`;\n}\n\nasync function parseJsonOrThrow<T>(response: Response): Promise<T> {\n  const body = await response.json().catch(() => null);\n  if (!response.ok) {\n    throw new Error(parseErrorText(response.status, body));\n  }\n  return body as T;\n}\n\nexport function isProviderKeyRotationError(error: unknown): boolean {\n  if (!(error instanceof Error)) return false;\n  const normalized = error.message.toLowerCase();\n  return (\n    normalized.includes(\"public key may have changed\") ||\n    normalized.includes(\"server key may have changed\")\n  );\n}\n\nlet cachedPublicKeyPem: string | null = null;\nlet cachedForgeKey: forge.pki.rsa.PublicKey | null = null;\n\nexport function clearProviderPublicKeyCache(): void {\n  cachedPublicKeyPem = null;","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/frontend/src/features/chat/api/providers-api.ts#L64-L100","documentation":"Fallback branch of parseErrorText in providers-api.ts: the error response body parsed but contained neither a formattable FastAPI detail nor a string message field (or failed to parse), so only the numeric status is reported. It backs all provider CRUD error paths (parseJsonOrThrow plus explicit deleteProviderConfig/cancelCodexOAuthFlow throws).","triggerScenarios":"Any /api/providers/* request failing with an empty or non-JSON error body — gateway 502 with an HTML page, a bare 500, or 401 from an auth layer that sends no JSON.","commonSituations":"Studio backend down behind a proxy; auth middleware short-circuiting; server error handlers not wrapping unexpected exceptions in the {detail} envelope.","solutions":["Map the status: 401/403 auth, 502/503 backend-down, 5xx server bug — then check the corresponding logs.","Ensure the backend's global exception handler returns JSON {detail} so clients get real messages.","Retry after backend recovery for 5xx."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { await updateProviderConfig(id, payload); }\ncatch (e) {\n  if (isProviderKeyRotationError(e)) { forceRefreshProviderKey(); return retry(); }\n  if (/Request failed \\((401|403)\\)/.test(e.message)) promptReauth();\n  else showError(e.message);\n}","preventionTips":["Use isProviderKeyRotationError to auto-recover key-rotation failures.","Ensure backend error handlers wrap all exceptions in {detail}.","Show the status code alongside the message so users can self-diagnose."],"tags":["providers","http","fallback-message","api"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}