{"record":{"id":"e9e2400ffe28074a","repo":"Budibase/budibase","slug":"failed-to-send-request","errorCode":null,"errorMessage":"Failed to send request","messagePattern":"Failed to send request","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/frontend-core/src/api/index.ts","lineNumber":200,"sourceCode":"      }\n    }\n\n    // Make request\n    let response: Response\n    try {\n      response = await fetch(url, {\n        method,\n        headers,\n        body: requestBody,\n        credentials: \"same-origin\",\n        signal,\n      })\n    } catch (error) {\n      delete cache[url]\n      if (signal?.aborted) {\n        throw error\n      }\n      throw makeError(\"Failed to send request\", url, method)\n    }\n\n    // Handle response\n    if (response.status >= 200 && response.status < 400) {\n      handleMigrations(response)\n      try {\n        if (response.status === 204) {\n          return undefined as ResponseT\n        } else if (parseResponse) {\n          return await parseResponse(response)\n        } else {\n          return (await response.json()) as ResponseT\n        }\n      } catch (error) {\n        delete cache[url]\n        throw `Failed to parse response: ${error}`\n      }\n    } else {","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/frontend-core/src/api/index.ts#L182-L218","documentation":"makeApiCall wraps the underlying fetch() call; if fetch itself rejects (network failure, DNS error, CORS block, mixed-content, server unreachable) it throws an APIError 'Failed to send request'. AbortError from an AbortSignal is re-thrown as-is; all other request-level errors are converted to this generic message. Note this fires only when the request never got a response — HTTP error statuses are handled separately afterwards.","triggerScenarios":"Any frontend-core API call where fetch() rejects: backend not running, wrong URL/port, network partition, CORS preflight failure, mixed http/https content, or invalid URL. Requests that were aborted via signal re-throw the original abort error instead.","commonSituations":"Local dev where the server (port 4001) or worker isn't started; proxy misconfiguration; calling an external API blocked by browser CORS; laptop offline or VPN drop mid-session.","solutions":["Confirm the backend service is running and reachable (e.g. curl http://localhost:4001/health).","Check the browser devtools Network/Console tab for the underlying fetch error (CORS, DNS, mixed content).","Verify the URL passed to the API call is absolute/valid and matches the configured proxy.","If the request was intentionally cancelled, check signal.aborted — abort errors surface unchanged and should be handled as cancellation, not failure."],"exampleFix":"// before: hard-coded wrong port\napi.get('http://localhost:4002/api/rows')\n// after: derive base URL from config/proxy\napi.get(`${window.location.origin}/api/rows`)","handlingStrategy":"retry","validationCode":"// pre-flight health check for local/self-hosted backends\nconst healthy = await fetch(`${baseUrl}/health`).then(r => r.ok).catch(() => false)\nif (!healthy) throw new Error(\"Backend unreachable before API call\")","typeGuard":"const isAbort = (e: unknown): e is DOMException =>\n  e instanceof DOMException && e.name === \"AbortError\"","tryCatchPattern":"try {\n  return await api.get(url)\n} catch (e) {\n  if (isAbort(e)) throw e // intentional cancellation\n  if (e?.message === \"Failed to send request\") {\n    await backoff(); return retry(() => api.get(url))\n  }\n  throw e\n}","preventionTips":["Ensure backend services are running before issuing calls in dev","Use relative/origin-derived URLs to avoid wrong-port mistakes","Check CORS and mixed-content rules when calling external APIs","Implement retry with backoff for transient network failures","Treat abort errors separately from network failures"],"tags":["network","fetch","api","frontend"],"backgroundTag":"network-request-failed","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}