decolua/9router · error · Error

Failed to load Codex reset credits

Error message

Failed to load Codex reset credits

What it means

handleViewCodexResetCredits GETs /api/usage/<connectionId>/codex-reset-credits (cache: no-store) to list the connection's available reset credits and throws result.error || result.message || 'Failed to load Codex reset credits' on non-OK. The route 404s for unknown connections, 400s for non-Codex or non-OAuth/access-token connections, 401s when the OAuth credential refresh fails, and 500s when the upstream credits lookup throws.

Source

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

        await fetchQuota(connectionId, provider);
        setLastUpdated(new Date());
      } catch (error) {
        setErrors((prev) => ({ ...prev, [connectionId]: error.message || "Failed to reset Codex limit" }));
      } finally {
        setResettingLimitId(null);
      }
    },
    [fetchQuota, resettingLimitId],
  );

  const handleViewCodexResetCredits = useCallback(async (connection) => {
    setResetCreditsState({ connection, loading: true, error: null, data: null });
    try {
      const response = await fetch(`/api/usage/${connection.id}/codex-reset-credits`, { cache: "no-store" });
      const result = await response.json().catch(() => ({}));
      if (!response.ok) {
        throw new Error(result.error || result.message || "Failed to load Codex reset credits");
      }
      const credits = Array.isArray(result.credits) ? [...result.credits] : [];
      credits.sort((a, b) => {
        const aTime = a.expiresAt ? new Date(a.expiresAt).getTime() : Number.POSITIVE_INFINITY;
        const bTime = b.expiresAt ? new Date(b.expiresAt).getTime() : Number.POSITIVE_INFINITY;
        return aTime - bTime;
      });
      setResetCreditsState({ connection, loading: false, error: null, data: { ...result, credits } });
    } catch (error) {
      setResetCreditsState({ connection, loading: false, error: error.message || "Failed to load Codex reset credits", data: null });
    }
  }, []);

  const handleDeleteConnection = useCallback(
    async (id) => {
      if (!confirm("Delete this connection?")) return;
      setDeletingId(id);
      try {

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Verify the connection still exists — reload the connections list (a 404 means it was deleted).
  2. Confirm the connection is provider=codex with authType oauth or access_token; otherwise the endpoint intentionally returns 400.
  3. On 'Credential refresh failed', re-authorize the Codex OAuth connection in the dashboard.
  4. Retry after checking network/proxy settings if the 500 stems from the upstream credits lookup.

Example fix

// before
throw new Error(result.error || result.message || "Failed to load Codex reset credits");
// after
throw new Error(result.error || result.message || `Failed to load Codex reset credits (HTTP ${response.status})`);
Defensive patterns

Strategy: validation

Validate before calling

if (!connection || connection.provider !== "codex") { setResetCreditsState({ connection: null, loading: false, error: "Not a Codex connection", data: null }); return; }
if (!["oauth", "access_token"].includes(connection.authType)) { setResetCreditsState({ connection: null, loading: false, error: "OAuth or access-token connection required", data: null }); return; }

Type guard

const isCreditsPayload = (r) => r && typeof r === "object" && (r.credits === undefined || Array.isArray(r.credits));

Try / catch

try {
  const response = await fetch(`/api/usage/${connection.id}/codex-reset-credits`, { cache: "no-store" });
  const result = await response.json().catch(() => ({}));
  if (!response.ok) throw new Error(result.error || result.message || `Failed to load credits (HTTP ${response.status})`);
  setResetCreditsState({ connection, loading: false, error: null, data: result.credits || [] });
} catch (e) {
  setResetCreditsState({ connection, loading: false, error: e.message, data: null });
}

Prevention

When it happens

Trigger: GET /api/usage/<id>/codex-reset-credits returns non-OK while opening the reset-credits modal: 404 'Connection not found', 400 'Codex reset credits are only available for Codex connections' / 'require an OAuth or access-token connection', 401 'Credential refresh failed: ...', or 500 from the upstream getCodexRateLimitResetCredits call.

Common situations: Opening the modal for a stale/deleted connection; connection authenticated via API key only; Codex OAuth token expired and refresh token invalid; network/proxy failure reaching the Codex usage endpoint.

Related errors


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