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

  1. Log in to the dashboard again — a 401 here means the session cookie expired or JWT_SECRET changed.
  2. Check the server console for DB errors and confirm the SQLite data directory (~/.9router or DATA_DIR) is writable.
  3. Confirm the fetch targets the same origin serving /api (reverse-proxy misroutes often yield non-JSON 404/502).
  4. 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

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


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/c81ebbcab8273b94. Report an issue: GitHub.