{"record":{"id":"a881e4ce94734251","repo":"ruvnet/RuView","slug":"request-failed","errorCode":null,"errorMessage":"Request failed","messagePattern":"Request failed","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ui/services/api.service.js","lineNumber":109,"sourceCode":"      // An earlier revision caught the server's RFC 6750 \"reauthentication\n      // required\" challenge and redirected to /oauth/start. That challenge can\n      // never be issued to a browser: browser sign-in requests `sensing:read`\n      // only and always will (see BROWSER_SIGNIN_SCOPE), so no browser session\n      // holds `sensing:admin`, so the freshness gate the challenge announces is\n      // never reached. Admin work goes through the CLI or a pasted bearer.\n      //\n      // Removed rather than left inert, because it was not merely dead — it\n      // ended in a promise that never settles. If any other 401 ever grew that\n      // header, every caller awaiting this would hang forever with no error.\n      // The server-side guard stays as a fail-closed backstop; the client has\n      // nothing to do about a flow that does not exist.\n\n      // Handle errors\n      if (!processedResponse.ok) {\n        const error = await processedResponse.json().catch(() => ({\n          message: `HTTP ${processedResponse.status}: ${processedResponse.statusText}`\n        }));\n        throw new Error(error.message || error.detail || 'Request failed');\n      }\n\n      // Parse JSON response\n      const data = await processedResponse.json().catch(() => null);\n      return data;\n\n    } catch (error) {\n      // Only log if not a connection refusal (expected when DensePose API is down)\n      if (error.message && !error.message.includes('Failed to fetch')) {\n        console.error('API Request Error:', error);\n      }\n      throw error;\n    }\n  }\n\n  // GET request\n  async get(endpoint, params = {}, options = {}) {\n    const url = buildApiUrl(endpoint, params);","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/ruvnet/RuView/blob/4685618388a5e49fad5b3005806f3bdd6a7c25c3/ui/services/api.service.js#L91-L127","documentation":"api.service.js throws on any non-ok response, preferring the JSON body's `message` then `detail` fields. 'Request failed' is the last-resort message, used only when the body parsed as JSON but contains neither a truthy `message` nor `detail` — a non-JSON body instead produces the 'HTTP <status>: <statusText>' fallback from the catch.","triggerScenarios":"Backend or gateway returns non-2xx with a JSON body like {\"error\":\"...\"}, {\"status\":500}, or {\"message\":\"\"} — envelopes this service does not recognize.","commonSituations":"Reverse proxies returning JSON errors in their own envelope; a framework version change moving the error text to a different key; production error sanitizers emptying message strings.","solutions":["Make the server's non-2xx responses include `message` or `detail` (FastAPI's default) so real text surfaces.","Patch the fallback to carry status context: error.message || error.detail || `Request failed (HTTP ${processedResponse.status})`.","When triaging, log processedResponse.status and the raw body to identify which endpoint and envelope shape is involved."],"exampleFix":"// before (ui/services/api.service.js)\nthrow new Error(error.message || error.detail || 'Request failed');\n// after\nthrow new Error(error.message || error.detail || `Request failed (HTTP ${processedResponse.status} ${processedResponse.statusText})`);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const data = await apiService.request('/zones', { method: 'GET' });\n} catch (error) {\n  if (error.message === 'Request failed') {\n    // body had no message/detail; surface generic failure with endpoint context\n    console.error('Unstructured error response from /zones');\n  } else if (error.message?.includes('Failed to fetch')) {\n    // DensePose API down / network refused — expected condition\n  }\n  throw error;\n}","preventionTips":["Make backend error responses include `message` or `detail` so this fallback never fires.","Distinguish network refusals ('Failed to fetch') from server-side failures in catch blocks.","Log the HTTP status alongside the message when triaging unstructured error bodies."],"tags":["http","api","ui","error-handling","backend-contract"],"backgroundTag":null,"analyzedSha":"4685618388a5e49fad5b3005806f3bdd6a7c25c3","analyzedAt":"2026-08-16T06:09:40.886Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}