{"record":{"id":"a06f1073cb24f349","repo":"decolua/9router","slug":"failed-to-get-copilot-token-error","errorCode":null,"errorMessage":"Failed to get Copilot token: ${error}","messagePattern":"Failed to get Copilot token: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/lib/oauth/services/github.js","lineNumber":117,"sourceCode":"    }\n  }\n\n  /**\n   * Get Copilot token using GitHub access token\n   */\n  async getCopilotToken(accessToken) {\n    const response = await fetch(`${GITHUB_CONFIG.copilotTokenUrl}`, {\n      headers: {\n        Authorization: `Bearer ${accessToken}`, // GitHub API typically uses Bearer\n        Accept: \"application/json\",\n        \"X-GitHub-Api-Version\": GITHUB_CONFIG.apiVersion,\n        \"User-Agent\": GITHUB_CONFIG.userAgent,\n      },\n    });\n\n    if (!response.ok) {\n      const error = await response.text();\n      throw new Error(`Failed to get Copilot token: ${error}`);\n    }\n\n    return await response.json();\n  }\n\n  /**\n   * Get user info using GitHub access token\n   */\n  async getUserInfo(accessToken) {\n    const response = await fetch(`${GITHUB_CONFIG.userInfoUrl}`, {\n      headers: {\n        Authorization: `Bearer ${accessToken}`, // GitHub API typically uses Bearer\n        Accept: \"application/json\",\n        \"X-GitHub-Api-Version\": GITHUB_CONFIG.apiVersion,\n        \"User-Agent\": GITHUB_CONFIG.userAgent,\n      },\n    });\n","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/lib/oauth/services/github.js#L99-L135","documentation":"GitHubService.getCopilotToken() exchanges the GitHub access token for a short-lived Copilot API token via GET to GITHUB_CONFIG.copilotTokenUrl. On a non-OK response the raw body is wrapped into `Failed to get Copilot token: ${error}` and thrown. Typically this means the authenticated GitHub account does not have an active Copilot subscription or the token lacks the Copilot scope.","triggerScenarios":"GET to the Copilot token endpoint (api.github.com/copilot_internal/v2/token) returns 403/401/404 — no active Copilot plan for the account, the GitHub token was issued without the required scopes, or the endpoint/API version became unavailable.","commonSituations":"GitHub account has no Copilot subscription (or trial expired); the organization blocks Copilot for its members; the Copilot API endpoint contract changed (the CLI's hardcoded URL or X-GitHub-Api-Version is stale); rate limiting (403 with rate-limit body).","solutions":["Verify the GitHub account has an active Copilot subscription (github.com/settings/copilot).","If using an organization account, confirm Copilot is enabled for your membership in org settings.","Re-authenticate so the token is issued with the scopes the CLI requests.","Check whether GITHUB_CONFIG.copilotTokenUrl / apiVersion still match the current Copilot API; update the library if upstream changed the endpoint."],"exampleFix":"// before\nif (!response.ok) {\n  const error = await response.text();\n  throw new Error(`Failed to get Copilot token: ${error}`);\n}\n// after\nif (!response.ok) {\n  const error = await response.text();\n  throw new Error(`Failed to get Copilot token (HTTP ${response.status}) — is Copilot enabled for this account? ${error}`);\n}","handlingStrategy":"validation","validationCode":"function assertCopilotTokenPayload(data) {\n  if (!data || typeof data.token !== 'string' || !data.expires_at) {\n    throw new Error('Copilot token response missing token/expires_at — is Copilot enabled for this account?');\n  }\n}","typeGuard":"function isCopilotTokenResponse(data) {\n  return data !== null && typeof data === 'object' && typeof data.token === 'string' && typeof data.expires_at === 'string';\n}","tryCatchPattern":"try {\n  const copilotToken = await service.getCopilotToken(accessToken);\n} catch (err) {\n  if (err.message.startsWith('Failed to get Copilot token')) {\n    console.error('Copilot token request failed — confirm the GitHub account has an active Copilot subscription and org-level Copilot is enabled.');\n  }\n  throw err;\n}","preventionTips":["Check github.com/settings/copilot shows an active subscription before running Copilot-dependent flows.","For org accounts, confirm the org policy permits Copilot for your membership.","Keep the CLI updated in case the Copilot token endpoint or required API version changes.","Handle 403 rate-limit bodies by backing off and retrying rather than failing permanently."],"tags":["network","http","github","copilot","permissions"],"backgroundTag":"http-403-forbidden","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}