decolua/9router · error · Error

GitHub API error: ${error}

Error message

GitHub API error: ${error}

What it means

After fetching the copilot_internal/user usage API, the library checks response.ok; when the upstream returns a non-2xx status it reads the body text and throws 'GitHub API error: <body>'. This surfaces upstream HTTP failures (401/403/404/5xx) with the raw upstream error payload embedded in the message.

Source

Thrown at open-sse/services/usage/github.js:39

    if (!accessToken) {
      throw new Error("No GitHub access token available. Please re-authorize the connection.");
    }

    // copilot_internal/user API requires GitHub OAuth token, not copilotToken
    const response = await proxyAwareFetch(U("github").url, {
      headers: {
        "Authorization": `token ${accessToken}`,
        "Accept": "application/json",
        "X-GitHub-Api-Version": GITHUB_CONFIG.apiVersion,
        "User-Agent": GITHUB_CONFIG.userAgent,
        "Editor-Version": "vscode/1.100.0",
        "Editor-Plugin-Version": "copilot-chat/0.26.7",
      },
    }, proxyOptions);

    if (!response.ok) {
      const error = await response.text();
      throw new Error(`GitHub API error: ${error}`);
    }

    const data = await response.json();

    // Handle different response formats (paid vs free)
    if (data.quota_snapshots) {
      // Paid plan format
      const snapshots = data.quota_snapshots;
      const resetAt = parseResetTime(data.quota_reset_date);

      return {
        plan: data.copilot_plan,
        resetDate: data.quota_reset_date,
        quotas: {
          chat: { ...formatGitHubQuotaSnapshot(snapshots.chat), resetAt },
          completions: { ...formatGitHubQuotaSnapshot(snapshots.completions), resetAt },
          premium_interactions: { ...formatGitHubQuotaSnapshot(snapshots.premium_interactions), resetAt },
        },

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Read the embedded body in the message — a 401/403 means re-authorize the GitHub connection to mint a new accessToken
  2. Confirm the account still has an active Copilot subscription/entitlement
  3. Retry after backoff if the body indicates 429 or a 5xx outage
  4. Check GitHub status (githubstatus.com) if errors are widespread

Example fix

// before
const usage = await getGitHubUsage(staleToken, data, proxy);
// after
try {
  const usage = await getGitHubUsage(staleToken, data, proxy);
} catch (e) {
  if (/GitHub API error: .*401|Bad credentials/i.test(e.message)) await reauthorizeGitHub(account);
  throw e;
}
Defensive patterns

Strategy: retry

Validate before calling

// No pre-call check can detect upstream status; ensure token freshness first
const tokenAge = Date.now() - (account.tokenObtainedAt || 0);
if (tokenAge > 12 * 3600 * 1000) await reauthorizeGitHub(account);

Try / catch

try {
  usage = await getGitHubUsage(token, data, proxy);
} catch (e) {
  const m = /GitHub API error: (.*)/.exec(e.message);
  if (m && /429|50[023]/.test(m[1])) {
    await sleep(backoff); return getGitHubUsage(token, data, proxy);
  }
  if (/401|Bad credentials/.test(m?.[1] || "")) await reauthorizeGitHub(account);
  throw e;
}

Prevention

When it happens

Trigger: The copilot_internal/user request returns a non-OK HTTP status: expired/revoked accessToken (401), token lacking Copilot entitlement (403/404), GitHub API outage (5xx), or rate-limited request (429).

Common situations: GitHub token revoked or expired after a password change; a fine-grained/PAT token without the right scopes; GitHub incident/outage; heavy polling of the usage endpoint hitting secondary rate limits.

Related errors


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