{"record":{"id":"fa82b186e304b47b","repo":"decolua/9router","slug":"github-api-error-error","errorCode":null,"errorMessage":"GitHub API error: ${error}","messagePattern":"GitHub API error: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"open-sse/services/usage/github.js","lineNumber":39,"sourceCode":"    if (!accessToken) {\n      throw new Error(\"No GitHub access token available. Please re-authorize the connection.\");\n    }\n\n    // copilot_internal/user API requires GitHub OAuth token, not copilotToken\n    const response = await proxyAwareFetch(U(\"github\").url, {\n      headers: {\n        \"Authorization\": `token ${accessToken}`,\n        \"Accept\": \"application/json\",\n        \"X-GitHub-Api-Version\": GITHUB_CONFIG.apiVersion,\n        \"User-Agent\": GITHUB_CONFIG.userAgent,\n        \"Editor-Version\": \"vscode/1.100.0\",\n        \"Editor-Plugin-Version\": \"copilot-chat/0.26.7\",\n      },\n    }, proxyOptions);\n\n    if (!response.ok) {\n      const error = await response.text();\n      throw new Error(`GitHub API error: ${error}`);\n    }\n\n    const data = await response.json();\n\n    // Handle different response formats (paid vs free)\n    if (data.quota_snapshots) {\n      // Paid plan format\n      const snapshots = data.quota_snapshots;\n      const resetAt = parseResetTime(data.quota_reset_date);\n\n      return {\n        plan: data.copilot_plan,\n        resetDate: data.quota_reset_date,\n        quotas: {\n          chat: { ...formatGitHubQuotaSnapshot(snapshots.chat), resetAt },\n          completions: { ...formatGitHubQuotaSnapshot(snapshots.completions), resetAt },\n          premium_interactions: { ...formatGitHubQuotaSnapshot(snapshots.premium_interactions), resetAt },\n        },","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/open-sse/services/usage/github.js#L21-L57","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Read the embedded body in the message — a 401/403 means re-authorize the GitHub connection to mint a new accessToken","Confirm the account still has an active Copilot subscription/entitlement","Retry after backoff if the body indicates 429 or a 5xx outage","Check GitHub status (githubstatus.com) if errors are widespread"],"exampleFix":"// before\nconst usage = await getGitHubUsage(staleToken, data, proxy);\n// after\ntry {\n  const usage = await getGitHubUsage(staleToken, data, proxy);\n} catch (e) {\n  if (/GitHub API error: .*401|Bad credentials/i.test(e.message)) await reauthorizeGitHub(account);\n  throw e;\n}","handlingStrategy":"retry","validationCode":"// No pre-call check can detect upstream status; ensure token freshness first\nconst tokenAge = Date.now() - (account.tokenObtainedAt || 0);\nif (tokenAge > 12 * 3600 * 1000) await reauthorizeGitHub(account);","typeGuard":null,"tryCatchPattern":"try {\n  usage = await getGitHubUsage(token, data, proxy);\n} catch (e) {\n  const m = /GitHub API error: (.*)/.exec(e.message);\n  if (m && /429|50[023]/.test(m[1])) {\n    await sleep(backoff); return getGitHubUsage(token, data, proxy);\n  }\n  if (/401|Bad credentials/.test(m?.[1] || \"\")) await reauthorizeGitHub(account);\n  throw e;\n}","preventionTips":["Poll the usage endpoint at a modest interval to avoid 429","Re-authorize on 401/403 instead of retrying with the same token","Watch GitHub status for 5xx clusters","Surface the embedded upstream body to users for diagnosis"],"tags":["http","github-copilot","api-error","auth"],"backgroundTag":"upstream-api-http-error","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}