decolua/9router · error · Error
Failed to fetch connections
Error message
Failed to fetch connections
What it means
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.
Source
Thrown at src/app/(dashboard)/dashboard/usage/components/ProviderLimits/index.js:193
const fetchConnections = useCallback(
async (targetPage = page) => {
try {
const params = new URLSearchParams({
page: String(targetPage),
pageSize: String(pageSize),
accountStatus: accountFilter,
sort: "priority",
});
if (providerFilter !== "all") {
params.set("provider", providerFilter);
}
const response = await fetch(
`/api/providers/client?${params.toString()}`,
);
if (!response.ok) throw new Error("Failed to fetch connections");
const data = await response.json();
const connectionList = data.connections || [];
const nextPagination = getSafePagination(data.pagination, pageSize);
const nextTotals = getSafeTotals(data.totals, connectionList.length);
setConnections(connectionList);
setProviderOptions(getProviderOptions(data.providerOptions));
setPagination(nextPagination);
setTotals(nextTotals);
setPage(getPaginationPageValue(data.pagination, targetPage));
return connectionList;
} catch (error) {
console.error("Error fetching connections:", error);
setConnections([]);
setProviderOptions([]);
setPagination({ page: 1, pageSize, total: 0, totalPages: 1 });
setTotals({ eligibleConnections: 0, providerFilteredConnections: 0 });View on GitHub (pinned to 90b52e06ff)
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.
Example fix
// before
if (!response.ok) throw new Error("Failed to fetch connections");
// after
if (!response.ok) throw new Error(`Failed to fetch connections (HTTP ${response.status}${response.status === 401 ? ", session expired — please log in" : ""})`); Defensive patterns
Strategy: retry
Validate before calling
const params = new URLSearchParams({ page: String(page), pageSize: String(pageSize) });
if (providerFilter) params.set("provider", providerFilter);
const sessionAlive = await fetch("/api/auth/session").then((r) => r.ok).catch(() => false);
if (!sessionAlive) { redirectToLogin(); return; } Type guard
const isConnectionsPayload = (d) => d && typeof d === "object" && (d.connections === undefined || Array.isArray(d.connections));
Try / catch
try {
const response = await fetch(`/api/providers/client?${params.toString()}`);
if (response.status === 401) { redirectToLogin(); return; }
if (!response.ok) throw new Error(`Failed to fetch connections (HTTP ${response.status})`);
} catch (e) {
setLoadError(e.message);
scheduleRetry();
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Failed to update quota visibility
- [${res.status}] ${text}
- Upstream error (${res.status})
- Edge TTS voices fetch failed: ${res.status}
- ElevenLabs API key required
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/c81ebbcab8273b94.
Report an issue: GitHub.