decolua/9router · error · Error

Failed to get user info: ${error}

Error message

Failed to get user info: ${error}

What it means

GitHubService.getUserInfo() calls GET https://api.github.com/user with the freshly obtained access token to fetch the authenticated user's profile. A non-OK response causes the raw body to be thrown as `Failed to get user info: ${error}`. Since the token was just minted by the device flow, this usually indicates a network/API problem rather than bad credentials — but a revoked or scope-less token will also fail here with 401.

Source

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

    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,
      },
    });

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

    return await response.json();
  }

  /**
   * Complete GitHub Copilot authentication flow
   */
  async authenticate() {
    try {
      // Get device code
      const deviceResponse = await this.getDeviceCode();
      
      // Poll for access token
      const tokenResponse = await this.pollAccessToken(
        deviceResponse.device_code, 
        deviceResponse.verification_uri, 
        deviceResponse.user_code

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Inspect the embedded body for a 403 rate-limit message; if so, wait for the rate-limit window or authenticate from a different IP.
  2. Re-run the device-flow authentication to obtain a fresh token, then retry.
  3. Verify api.github.com is reachable (curl -i https://api.github.com/user with the token) and no proxy strips Authorization.
  4. Retry later if GitHub status (githubstatus.com) reports an API incident.

Example fix

// before
if (!response.ok) {
  const error = await response.text();
  throw new Error(`Failed to get user info: ${error}`);
}
// after
if (!response.ok) {
  const error = await response.text();
  throw new Error(`Failed to get user info (HTTP ${response.status}): ${error}`);
}
Defensive patterns

Strategy: retry

Validate before calling

async function assertUserFetchable(accessToken) {
  const res = await fetch('https://api.github.com/user', {
    headers: { Authorization: `Bearer ${accessToken}`, Accept: 'application/json', 'User-Agent': 'app' },
  });
  if (res.status === 403 && res.headers.get('x-ratelimit-remaining') === '0') {
    throw new Error('GitHub API rate limit exhausted — wait for reset before authenticating');
  }
  if (!res.ok) throw new Error(`GitHub /user pre-check failed: HTTP ${res.status}`);
}

Type guard

function isGitHubUser(data) {
  return data !== null && typeof data === 'object' && typeof data.login === 'string' && typeof data.id === 'number';
}

Try / catch

try {
  const userInfo = await service.getUserInfo(accessToken);
} catch (err) {
  if (err.message.startsWith('Failed to get user info')) {
    console.error('GitHub /user call failed — check rate limits (403), token validity (401), or api.github.com reachability, then retry.');
  }
  throw err;
}

Prevention

When it happens

Trigger: GET to api.github.com/user returns non-2xx: 401 (bad/insufficiently-scoped token), 403 (rate limit exhausted for the IP), 5xx from GitHub, or an intercepted body from a proxy/portal.

Common situations: Shared IP (corporate NAT/CI) hitting GitHub's unauthenticated rate limits; a proxy stripping the Authorization header; GitHub API incident; User-Agent or X-GitHub-Api-Version rejected by an API gateway.

Related errors


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