decolua/9router · error · Error

Failed to get Copilot token

Error message

Failed to get Copilot token: ${error}

What it means

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.

Solutions

  1. Verify the GitHub account has an active Copilot subscription (github.com/settings/copilot).
  2. If using an organization account, confirm Copilot is enabled for your membership in org settings.
  3. Re-authenticate so the token is issued with the scopes the CLI requests.
  4. Check whether GITHUB_CONFIG.copilotTokenUrl / apiVersion still match the current Copilot API; update the library if upstream changed the endpoint.

Example fix

// before
if (!response.ok) {
  const error = await response.text();
  throw new Error(`Failed to get Copilot token: ${error}`);
}
// after
if (!response.ok) {
  const error = await response.text();
  throw new Error(`Failed to get Copilot token (HTTP ${response.status}) — is Copilot enabled for this account? ${error}`);
}
Defensive patterns

Strategy: validation

Validate before calling

function assertCopilotTokenPayload(data) {
  if (!data || typeof data.token !== 'string' || !data.expires_at) {
    throw new Error('Copilot token response missing token/expires_at — is Copilot enabled for this account?');
  }
}

Type guard

function isCopilotTokenResponse(data) {
  return data !== null && typeof data === 'object' && typeof data.token === 'string' && typeof data.expires_at === 'string';
}

Try / catch

try {
  const copilotToken = await service.getCopilotToken(accessToken);
} catch (err) {
  if (err.message.startsWith('Failed to get Copilot token')) {
    console.error('Copilot token request failed — confirm the GitHub account has an active Copilot subscription and org-level Copilot is enabled.');
  }
  throw err;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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).

Related errors


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

Appendix: source

Thrown at src/lib/oauth/services/github.js:117

    }
  }

  /**
   * Get Copilot token using GitHub access token
   */
  async getCopilotToken(accessToken) {
    const response = await fetch(`${GITHUB_CONFIG.copilotTokenUrl}`, {
      headers: {
        Authorization: `Bearer ${accessToken}`, // GitHub API typically uses Bearer
        Accept: "application/json",
        "X-GitHub-Api-Version": GITHUB_CONFIG.apiVersion,
        "User-Agent": GITHUB_CONFIG.userAgent,
      },
    });

    if (!response.ok) {
      const error = await response.text();
      throw new Error(`Failed to get Copilot token: ${error}`);
    }

    return await response.json();
  }

  /**
   * Get user info using GitHub access token
   */
  async getUserInfo(accessToken) {
    const response = await fetch(`${GITHUB_CONFIG.userInfoUrl}`, {
      headers: {
        Authorization: `Bearer ${accessToken}`, // GitHub API typically uses Bearer
        Accept: "application/json",
        "X-GitHub-Api-Version": GITHUB_CONFIG.apiVersion,
        "User-Agent": GITHUB_CONFIG.userAgent,
      },
    });

View on GitHub (pinned to 90b52e06ff)