decolua/9router · warning · Error

Failed to update quota visibility

Error message

Failed to update quota visibility

What it means

ProviderLimits persists per-provider quota visibility (hidden rows) by PATCHing /api/settings with { quotaVisibility }. On any non-OK response it throws 'Failed to update quota visibility', logs the error, and rolls the local visibility state back to previousVisibility. Note the thrown message is fixed — the actual HTTP status is only visible in the console.error.

Source

Thrown at src/app/(dashboard)/dashboard/usage/components/ProviderLimits/index.js:584

      await fetch("/api/settings", {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ [settingsKey]: cfg }),
      });
    } catch {
      setAutoPingMaps(previous);
    }
  }, [autoPingMaps]);

  const updateQuotaVisibility = useCallback(async (nextVisibility, previousVisibility) => {
    setQuotaVisibility(nextVisibility);
    try {
      const response = await fetch("/api/settings", {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ quotaVisibility: nextVisibility }),
      });
      if (!response.ok) throw new Error("Failed to update quota visibility");
    } catch (error) {
      console.error("Error updating quota visibility:", error);
      setQuotaVisibility(previousVisibility);
    }
  }, []);

  const handleHideQuota = useCallback((provider, quota) => {
    const key = getQuotaVisibilityKey(quota);
    if (!provider || !key) return;

    const previous = quotaVisibility;
    const providerVisibility = previous[provider] || {};
    const hidden = new Set(providerVisibility.hidden || []);
    hidden.add(key);
    const next = {
      ...previous,
      [provider]: {
        ...providerVisibility,

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Log back into the dashboard — 401 from /api/settings means the session cookie is no longer valid.
  2. Check server logs for settings-save failures and ensure the data directory (~/.9router or DATA_DIR) is writable.
  3. Retry the toggle; the UI already reverts the optimistic change, so a retry after re-login is safe.
  4. Include response.status in the thrown message so failures are diagnosable without the console.

Example fix

// before
if (!response.ok) throw new Error("Failed to update quota visibility");
// after
if (!response.ok) throw new Error(`Failed to update quota visibility (HTTP ${response.status})`);
Defensive patterns

Strategy: try-catch

Validate before calling

const sessionOk = await fetch("/api/settings", { method: "GET" }).then((r) => r.ok).catch(() => false);
if (!sessionOk) { redirectToLogin(); return; }
const isValidVisibility = (v) => v && typeof v === "object" && Object.values(v).every((b) => typeof b === "boolean");

Type guard

const isVisibilityMap = (v) => v !== null && typeof v === "object" && !Array.isArray(v) && Object.values(v).every((x) => typeof x === "boolean");

Try / catch

const previousVisibility = quotaVisibility;
setQuotaVisibility(nextVisibility);
try {
  const response = await fetch("/api/settings", { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ quotaVisibility: nextVisibility }) });
  if (response.status === 401) { redirectToLogin(); return; }
  if (!response.ok) throw new Error(`Failed to update quota visibility (HTTP ${response.status})`);
} catch (error) {
  console.error("Error updating quota visibility:", error);
  setQuotaVisibility(previousVisibility);
}

Prevention

When it happens

Trigger: PATCH /api/settings with body { quotaVisibility: nextVisibility } returns non-OK — most commonly 401 when the dashboard session expired, 400 on body validation, or 500 when persisting settings to the SQLite store fails — inside the visibility toggle handler at ProviderLimits/index.js:584.

Common situations: Dashboard session expired mid-use (JWT_SECRET rotated or cookie expired); settings DB write failure (read-only data dir, disk full); server restarting while the toggle is clicked.

Related errors


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