decolua/9router · warning

[Usage] ${connection.provider}: force refresh failed: ${retr

Error message

[Usage] ${connection.provider}: force refresh failed: ${retryError.message}

What it means

Console.warn in the GET usage handler when the force-refresh retry path fails. If the provider usage call reports an expired OAuth token (isAuthExpiredMessage) and a refresh token exists, the route refreshes credentials and re-fetches usage; if the refresh or the retry usage fetch throws, this message is logged and the original stale `usage` object is returned in the JSON response.

Source

Thrown at src/app/api/usage/[connectionId]/route.js:182

        console.error("[Usage API] Credential refresh failed:", refreshError);
        return Response.json({
          error: `Credential refresh failed: ${refreshError.message}`
        }, { status: 401 });
      }
    }

    // Fetch usage from provider API
    let usage = await getUsageForProvider(connection, proxyOptions, { force });

    // If provider returned an auth-expired message instead of throwing,
    // force-refresh token and retry once (OAuth only)
    if (isOAuth && isAuthExpiredMessage(usage) && connection.refreshToken) {
      try {
        const retryResult = await refreshAndUpdateCredentials(connection, true, proxyOptions);
        connection = retryResult.connection;
        usage = await getUsageForProvider(connection, proxyOptions, { force });
      } catch (retryError) {
        console.warn(`[Usage] ${connection.provider}: force refresh failed: ${retryError.message}`);
      }
    }

    return Response.json(usage);
  } catch (error) {
    const provider = connection?.provider ?? "unknown";
    console.warn(`[Usage] ${provider}: ${error.message}`);
    return Response.json({ error: error.message }, { status: 500 });
  }
}

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Re-authenticate the OAuth connection in the dashboard to obtain a fresh refresh token.
  2. Check the underlying retryError.message (e.g. invalid_grant vs ENOTFOUND) to distinguish credential death from network issues.
  3. Verify proxy settings and outbound connectivity to the provider's token/usage endpoints.
  4. Retry the GET; if it persists, disable/re-add the connection.

Example fix

// before
catch (retryError) {
  console.warn(`[Usage] ${connection.provider}: force refresh failed: ${retryError.message}`);
}
// after
catch (retryError) {
  console.warn(`[Usage] ${connection.provider}: force refresh failed: ${retryError.message}`);
  usage = { ...usage, authError: retryError.message, needsReauth: retryError.message.includes("invalid_grant") };
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Check connection health before querying usage
if (!conn.refreshToken) console.warn("No refresh token — usage may fail on expired access token");

Type guard

function isUsagePayload(u) { return u && typeof u === "object" && !u.error; }

Try / catch

try {
  const res = await fetch(`/api/usage/${connId}`);
  const usage = await res.json();
  if (usage?.needsReauth || usage?.authError) await reauthenticate(connId);
} catch (e) { /* handle fetch failure */ }

Prevention

When it happens

Trigger: GET /api/usage/[connectionId] on an OAuth provider where the usage response indicates an expired token, and refreshAndUpdateCredentials throws (revoked refresh token, token endpoint unreachable, bad proxy) or getUsageForProvider throws on the retry (network error).

Common situations: Accounts idle past the refresh token lifetime; upstream provider OAuth endpoint outage; proxy misconfiguration; expired/revoked refresh tokens after password change or app deauthorization at the provider.

Related errors


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