decolua/9router · error · Error

${callbackParams.error_description || callbackParams.error}

Error message

${callbackParams.error_description || callbackParams.error}

What it means

During the Gemini OAuth authorization-code flow, the local callback server captures query params from Google's redirect. If Google redirects back with an `error` (and optionally `error_description`) parameter instead of an authorization code, connect() throws an Error with the description (or bare error code) at gemini.js:205. This is the standard OAuth2 error redirect (RFC 6749 §4.1.2.1), e.g. `access_denied`.

Source

Thrown at src/lib/oauth/services/gemini.js:205

      await new Promise((resolve, reject) => {
        const timeout = setTimeout(() => {
          reject(new Error("Authentication timeout (5 minutes)"));
        }, 300000);

        const checkInterval = setInterval(() => {
          if (callbackParams) {
            clearInterval(checkInterval);
            clearTimeout(timeout);
            resolve();
          }
        }, 100);
      });

      close();

      if (callbackParams.error) {
        throw new Error(callbackParams.error_description || callbackParams.error);
      }

      if (!callbackParams.code) {
        throw new Error("No authorization code received");
      }

      spinner.start("Exchanging code for tokens...");

      // Exchange code for tokens
      const tokens = await this.exchangeCode(callbackParams.code, redirectUri);

      spinner.text = "Fetching user info...";

      // Get user info
      const userInfo = await this.getUserInfo(tokens.access_token);

      spinner.text = "Fetching project ID...";

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Retry the connect flow and click Allow on the Google consent screen.
  2. If the error is `redirect_uri_mismatch`, confirm the OAuth client (GEMINI_CONFIG.clientId) registers the exact `http://localhost:<port>/callback` redirect URI.
  3. If `access_denied` or `unverified_app`, add your Google account as a test user on the project's OAuth consent screen.
  4. Read the thrown description (error_description) — it names the exact OAuth error code to address.
Defensive patterns

Strategy: try-catch

Validate before calling

const authUrl = new URL(authUrlString);
const redirectUri = authUrl.searchParams.get('redirect_uri');
if (!redirectUri || !redirectUri.startsWith('http://localhost:')) {
  throw new Error('Invalid redirect_uri configured for Gemini OAuth client');
}

Type guard

function isOAuthErrorParams(params) {
  return params !== null && typeof params === 'object' && typeof params.error === 'string' && params.error.length > 0;
}

Try / catch

try {
  await geminiService.connect();
} catch (err) {
  if (/access_denied|redirect_uri_mismatch|unverified/i.test(err.message)) {
    console.error(`Google authorization failed (${err.message}). Retry and click Allow; add your account as a test user if the app is unverified.`);
  }
  throw err;
}

Prevention

When it happens

Trigger: The user denies consent on Google's authorization page, Google rejects the request (e.g. redirect_uri/client_id mismatch, invalid scope), or the app is unverified and the user clicks through an 'unsafe' warning canceling the flow — any of which sends `?error=...` to http://localhost:<port>/callback.

Common situations: User clicked 'Cancel' on the consent screen; the Google Cloud project's OAuth consent screen is in testing mode and the user's email is not added as a test user; the OAuth client's authorized redirect URI doesn't include the exact localhost callback, so Google returns redirect_uri_mismatch.

Related errors


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