{"record":{"id":"1e8bd82e35ccaf87","repo":"chatboxai/chatbox","slug":"status-code-response-status","errorCode":null,"errorMessage":"Status Code ${response.status}","messagePattern":"Status Code (.+?)","errorType":"http","errorClass":"ApiError","httpStatus":null,"severity":"error","filePath":"src/renderer/utils/mobile-request.ts","lineNumber":91,"sourceCode":"        },\n      })\n    } catch (err) {\n      console.warn('Native streaming unavailable, falling back', err)\n    }\n  }\n\n  const response = await CapacitorHttp.request({\n    url,\n    method,\n    headers: headerObj,\n    data: body,\n    responseType: 'text',\n  })\n\n  const rawData = typeof response.data === 'string' ? response.data : JSON.stringify(response.data)\n  // Treat status 0 or < 200 as errors, in addition to >= 400\n  if (response.status === 0 || response.status < 200 || response.status >= 400) {\n    throw new ApiError(`Status Code ${response.status}`, rawData, response.status)\n  }\n  const responseData = rawData\n\n  if (isStreaming) {\n    const stream = new ReadableStream({\n      start(controller) {\n        controller.enqueue(new TextEncoder().encode(responseData))\n        controller.close()\n      },\n    })\n    return new Response(stream, {\n      status: response.status,\n      headers: { ...response.headers, 'Content-Type': 'text/event-stream' },\n    })\n  }\n\n  return new Response(responseData, {\n    status: response.status,","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/chatboxai/chatbox/blob/81571269addb6bafb589a920b2883f1e1e084fd1/src/renderer/utils/mobile-request.ts#L73-L109","documentation":"Thrown by the mobile HTTP shim (CapacitorHttp) after a request completes: when response.status is 0 (no response / CORS / native failure), < 200, or >= 400, an ApiError is constructed with the raw body as its message payload and the numeric status. It is the single failure exit for all mobile network calls routed through this shim.","triggerScenarios":"CapacitorHttp.request resolves with a non-2xx status: server returns 4xx/5xx; status 0 from a DNS/CORS/native-network failure; rawData is the stringified body (HTML error page, JSON error, or empty). The thrown ApiError carries rawData as responseBody and response.status as statusCode.","commonSituations":"Provider endpoint down (502/503/504); invalid API key (401); rate limit (429); mobile platform blocking the URL via App Transport Security; CORS misconfiguration on a self-hosted endpoint; offline/no network giving status 0; server returning HTML instead of JSON.","solutions":["Read the ApiError.statusCode — 401/403 → fix API key/headers; 429 → back off and retry; 5xx → provider outage, retry with exponential backoff; 0 → check device connectivity and ATS/CORS config.","Inspect ApiError.responseBody for the server's actual error message — HTML bodies typically indicate a gateway/proxy error, not an API error.","For self-hosted providers, ensure the endpoint sends permissive CORS headers and HTTPS (ATS blocks plain HTTP on iOS).","If status is consistently 0 on Android, verify the network_security_config / cleartext policy permits the host."],"exampleFix":"// before\nif (response.status === 0 || response.status < 200 || response.status >= 400) {\n  throw new ApiError(`Status Code ${response.status}`, rawData, response.status)\n}\n// after — distinguish no-response from HTTP error for clearer UX\nif (response.status === 0) {\n  throw new ApiError('No response (network/CORS/ATS failure)', rawData, 0)\n}\nif (response.status < 200 || response.status >= 400) {\n  throw new ApiError(`Status Code ${response.status}`, rawData, response.status)\n}","handlingStrategy":"retry","validationCode":"// Pre-validate the URL scheme and connectivity before issuing the CapacitorHttp call.\nfunction isMobileRequestLikelyToSucceed(url: string): boolean {\n  try {\n    const u = new URL(url)\n    return u.protocol === 'https:' || u.protocol === 'http:'\n  } catch { return false }\n}","typeGuard":"function isApiErrorWithStatus(e: unknown): e is ApiError & { statusCode: number } {\n  return e instanceof ApiError && typeof (e as any).statusCode === 'number'\n}","tryCatchPattern":"try {\n  return await mobileRequest(url, opts)\n} catch (e) {\n  if (e instanceof ApiError && typeof e.statusCode === 'number') {\n    if (e.statusCode === 0) showUser('Network unavailable. Check your connection.')\n    else if (e.statusCode >= 500) return retryWithBackoff(() => mobileRequest(url, opts))\n    else if (e.statusCode === 401) rotateApiKey()\n  }\n  throw e\n}","preventionTips":["Whitelist hosts in network_security_config (Android) and ATS (iOS) before shipping.","Distinguish status 0 (network/CORS) from HTTP errors in the error UI so users get the right remediation.","Inspect ApiError.responseBody before assuming JSON — gateway errors are often HTML."],"tags":["network","mobile","capacitor","http-status"],"backgroundTag":null,"analyzedSha":"81571269addb6bafb589a920b2883f1e1e084fd1","analyzedAt":"2026-08-12T21:51:44.981Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}