{"record":{"id":"c81ebbcab8273b94","repo":"decolua/9router","slug":"failed-to-fetch-connections","errorCode":null,"errorMessage":"Failed to fetch connections","messagePattern":"Failed to fetch connections","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/app/(dashboard)/dashboard/usage/components/ProviderLimits/index.js","lineNumber":193,"sourceCode":"\n  const fetchConnections = useCallback(\n    async (targetPage = page) => {\n      try {\n        const params = new URLSearchParams({\n          page: String(targetPage),\n          pageSize: String(pageSize),\n          accountStatus: accountFilter,\n          sort: \"priority\",\n        });\n\n        if (providerFilter !== \"all\") {\n          params.set(\"provider\", providerFilter);\n        }\n\n        const response = await fetch(\n          `/api/providers/client?${params.toString()}`,\n        );\n        if (!response.ok) throw new Error(\"Failed to fetch connections\");\n\n        const data = await response.json();\n        const connectionList = data.connections || [];\n        const nextPagination = getSafePagination(data.pagination, pageSize);\n        const nextTotals = getSafeTotals(data.totals, connectionList.length);\n\n        setConnections(connectionList);\n        setProviderOptions(getProviderOptions(data.providerOptions));\n        setPagination(nextPagination);\n        setTotals(nextTotals);\n        setPage(getPaginationPageValue(data.pagination, targetPage));\n        return connectionList;\n      } catch (error) {\n        console.error(\"Error fetching connections:\", error);\n        setConnections([]);\n        setProviderOptions([]);\n        setPagination({ page: 1, pageSize, total: 0, totalPages: 1 });\n        setTotals({ eligibleConnections: 0, providerFilteredConnections: 0 });","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/app/(dashboard)/dashboard/usage/components/ProviderLimits/index.js#L175-L211","documentation":"ProviderLimits fetches the paginated provider-connection list from /api/providers/client and throws this fixed message whenever response.ok is false. The route may return 401 when the dashboard session is invalid, or 5xx when the database read fails, so the UI shows a generic fetch failure regardless of the actual HTTP cause.","triggerScenarios":"GET /api/providers/client?<provider=&search=&page=&pageSize=...> returns any non-OK status — typically 401 unauthorized (expired dashboard session cookie) or 500 (DB error) — inside the connections-loading effect at ProviderLimits/index.js:193.","commonSituations":"Dashboard JWT session expired; server restarted with a different JWT_SECRET invalidating cookies; backend DB (SQLite layer) unavailable; wrong port/proxy returning an HTML error page instead of JSON.","solutions":["Log in to the dashboard again — a 401 here means the session cookie expired or JWT_SECRET changed.","Check the server console for DB errors and confirm the SQLite data directory (~/.9router or DATA_DIR) is writable.","Confirm the fetch targets the same origin serving /api (reverse-proxy misroutes often yield non-JSON 404/502).","Improve the error message to include response.status so the actual cause is visible instead of the generic text."],"exampleFix":"// before\nif (!response.ok) throw new Error(\"Failed to fetch connections\");\n// after\nif (!response.ok) throw new Error(`Failed to fetch connections (HTTP ${response.status}${response.status === 401 ? \", session expired — please log in\" : \"\"})`);","handlingStrategy":"retry","validationCode":"const params = new URLSearchParams({ page: String(page), pageSize: String(pageSize) });\nif (providerFilter) params.set(\"provider\", providerFilter);\nconst sessionAlive = await fetch(\"/api/auth/session\").then((r) => r.ok).catch(() => false);\nif (!sessionAlive) { redirectToLogin(); return; }","typeGuard":"const isConnectionsPayload = (d) => d && typeof d === \"object\" && (d.connections === undefined || Array.isArray(d.connections));","tryCatchPattern":"try {\n  const response = await fetch(`/api/providers/client?${params.toString()}`);\n  if (response.status === 401) { redirectToLogin(); return; }\n  if (!response.ok) throw new Error(`Failed to fetch connections (HTTP ${response.status})`);\n} catch (e) {\n  setLoadError(e.message);\n  scheduleRetry();\n}","preventionTips":["Handle 401 distinctly — redirect to login instead of showing a generic fetch error.","Set a stable JWT_SECRET so server restarts don't invalidate sessions.","Retry transient 5xx with backoff before surfacing an error."],"tags":["http-error","authentication","data-fetching"],"backgroundTag":"http-401-unauthorized","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}