decolua/9router · error · Error

GitHub authentication failed: ${error.message}

Error message

GitHub authentication failed: ${error.message}

What it means

GitHubService.authenticate() orchestrates the whole device flow: getDeviceCode → pollAccessToken → getCopilotToken → getUserInfo. Any error thrown by those steps is caught and re-wrapped as `GitHub authentication failed: ${error.message}` at github.js:181. This is a wrapper message — the root cause is the inner error text (e.g. 'Device code expired', 'Access denied', or an HTTP failure).

Source

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

      const userInfo = await this.getUserInfo(tokenResponse.access_token);
      
      console.log(`\n✅ Successfully authenticated as ${userInfo.login}`);
      
      return {
        accessToken: tokenResponse.access_token,
        copilotToken: copilotToken.token,
        refreshToken: null, // GitHub device flow doesn't return refresh token
        expiresIn: copilotToken.expires_at,
        userInfo: {
          id: userInfo.id,
          login: userInfo.login,
          name: userInfo.name,
          email: userInfo.email,
        },
        copilotTokenInfo: copilotToken,
      };
    } catch (error) {
      throw new Error(`GitHub authentication failed: ${error.message}`);
    }
  }

  /**
   * Connect to server with GitHub credentials
   */
  async connect() {
    try {
      // Authenticate with GitHub
      const authResult = await this.authenticate();
      
      // Send credentials to server
      const { server, token, userId } = await import("../config/index.js").then(m => m.getServerCredentials());
      const spinner = (await import("../utils/ui.js")).spinner("Connecting to server...").start();
      
      const response = await fetch(`${server}/api/cli/providers/github`, {
        method: "POST",
        headers: {

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Read the text after 'GitHub authentication failed:' — it contains the inner error; map it to the specific step and fix listed for errors 263–268.
  2. If the inner message is empty, add temporary logging of the caught error (message + stack) to identify the failing step.
  3. Re-run authenticate() from a network that can reach github.com and complete the browser authorization promptly.
  4. Consider preserving the original error (`throw new Error(..., { cause: error })`) for better stack traces.

Example fix

// before
} catch (error) {
  throw new Error(`GitHub authentication failed: ${error.message}`);
}
// after
} catch (error) {
  throw new Error(`GitHub authentication failed: ${error.message}`, { cause: error });
}
Defensive patterns

Strategy: try-catch

Validate before calling

async function canReachGitHub() {
  const res = await fetch('https://github.com', { method: 'HEAD' }).catch(() => null);
  if (!res) throw new Error('GitHub unreachable — device authentication will fail');
}

Type guard

function isAuthResult(r) {
  return r !== null && typeof r === 'object' && typeof r.accessToken === 'string' && typeof r.copilotToken === 'string' && r.userInfo?.login;
}

Try / catch

try {
  const auth = await service.authenticate();
} catch (err) {
  const inner = err.cause ?? err;
  console.error(`GitHub auth failed at: ${inner.message}`); // unwrap to see the real failing step
  if (inner.message === 'Device code expired') return retryWithFreshCode();
  if (inner.message === 'Access denied') return promptUserToRetry();
  throw err;
}

Prevention

When it happens

Trigger: Any failure inside authenticate(): device-code request failed (263), user never authorized in time (264), user denied (265), unrecognized poll error (266), Copilot token rejected (267), or user-info fetch failed (268).

Common situations: All the underlying situations above; additionally, because the wrapper discards the original stack, developers often see only this generic line when debugging CI or scripted runs where the inner spinner output was suppressed.

Understand the failure class

Related errors


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