{"record":{"id":"9a8220fb4d8f3efd","repo":"unslothai/unsloth","slug":"request-failed-status","errorCode":null,"errorMessage":"Request failed (${status})","messagePattern":"Request failed \\((.+?)\\)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"studio/frontend/src/features/chat/api/mcp-servers-api.ts","lineNumber":52,"sourceCode":"    if (formatted) return formatted;\n    if (typeof message === \"string\" && message) return message;\n  }\n  return `Request failed (${status})`;\n}\n\nasync function mcpRequest<T>(\n  path: string,\n  init?: { method?: string; body?: object },\n): Promise<T> {\n  const response = await authFetch(`/api/mcp/servers${path}`, {\n    method: init?.method,\n    headers: init?.body ? { \"Content-Type\": \"application/json\" } : undefined,\n    body: init?.body ? JSON.stringify(init.body) : undefined,\n  });\n  // 204 No Content (DELETE) has no body — calling .json() would throw.\n  if (response.status === 204) return undefined as T;\n  const json = await response.json().catch(() => null);\n  if (!response.ok) throw new Error(parseErrorText(response.status, json));\n  return json as T;\n}\n\nexport function listMcpServers(): Promise<McpServerConfig[]> {\n  return mcpRequest(\"/\");\n}\n\nexport function createMcpServer(payload: {\n  displayName: string;\n  url: string;\n  headers?: Record<string, string>;\n  isEnabled?: boolean;\n  useOauth?: boolean;\n}): Promise<McpServerConfig> {\n  return mcpRequest(\"/\", {\n    method: \"POST\",\n    body: {\n      display_name: payload.displayName,","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/frontend/src/features/chat/api/mcp-servers-api.ts#L34-L70","documentation":"Generic failure from mcpRequest, the shared wrapper for all /api/mcp/servers CRUD calls. After special-casing 204 (DELETE success with no body), it parses the JSON body and throws when !response.ok. parseErrorText prefers a FastAPI detail (formatted via formatFastApiDetail) or message field, and this listed fallback 'Request failed (status)' only appears when the error body is empty or unparseable.","triggerScenarios":"listMcpServers ('/'), createMcpServer, update, delete, or health-check calls returning 4xx/5xx — e.g. invalid MCP server URL (422), duplicate server name, auth failure, or backend unable to reach the configured MCP server.","commonSituations":"Registering an MCP server with an unreachable/wrong URL; header schema violations; server-side MCP connection failures surfacing as 502; expired session.","solutions":["Read the message: a real detail from the backend names the failing field or connection error; the bare 'Request failed (status)' fallback means the body was empty — check backend logs.","Validate the MCP server URL and headers before submitting.","Confirm the MCP server itself is reachable from the backend (not just from the browser).","Re-auth if status is 401/403."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Validate before create\nconst url = new URL(payload.url); // throws on malformed URL\nif (!/^https?:$/.test(url.protocol)) throw new Error('MCP server URL must be http(s)');","typeGuard":null,"tryCatchPattern":"try { await createMcpServer(payload); }\ncatch (e) { showFormError(e.message); // message carries FastAPI detail when present }","preventionTips":["Client-side validate URL/header shape before hitting the API.","Health-check MCP reachability from the backend, not the browser.","Distinguish empty-body fallback messages ('Request failed (n)') — they mean 'check server logs'."],"tags":["mcp","http","api","validation"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}