decolua/9router · error

${callbackParams.error_description || callbackParams.error}

Error message

${callbackParams.error_description || callbackParams.error}

What it means

The xAI OAuth provider returned an authorization error to the local loopback callback (e.g. ?error=access_denied&error_description=...). connect() surfaces the provider's error_description, or the bare error code if no description was sent, instead of proceeding to the token exchange. This is the OAuth spec-defined failure path of the authorization-code flow, thrown before any tokens are requested.

Source

Thrown at src/lib/oauth/services/xai.js:217

      console.log("\nOpening browser for xAI authentication...");
      console.log(`If browser doesn't open, visit:\n${authUrl}\n`);
      await open(authUrl);

      spinner.start("Waiting for xAI authorization...");
      await new Promise((resolve, reject) => {
        const timeout = setTimeout(() => reject(new Error("Authentication timeout (5 minutes)")), 300000);
        const iv = setInterval(() => {
          if (callbackParams) {
            clearInterval(iv);
            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");
      if (callbackParams.state !== state) throw new Error("Invalid state parameter");

      spinner.start("Exchanging code for tokens...");
      const tokens = await this.exchangeXaiCode({
        tokenUrl,
        code: callbackParams.code,
        redirectUri,
        codeVerifier,
      });

      const email = decodeIdTokenEmail(tokens.id_token);
      spinner.succeed("xAI connected successfully!");
      return { tokens, email };
    } catch (error) {
      spinner.fail(`Failed: ${error.message}`);
      throw error;

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Read the thrown message (it is xAI's error_description) and address the specific cause: access_denied means the user must re-run connect() and approve the consent prompt
  2. Re-run connect() and complete authorization in the browser window instead of cancelling
  3. Verify XAI_CONFIG.clientId/redirect settings and that discoverEndpoints() resolves valid xAI authorize/token URLs
  4. Check the xAI account/organization has the necessary entitlements for the requested scopes
  5. Retry later if the message indicates a server-side xAI issue (server_error, temporarily_unavailable)

Example fix

// before: denial surfaces only as a raw CLI failure
await xai.connect();
// after: handle the user-denied case explicitly
try {
  await xai.connect();
} catch (e) {
  if (/access_denied/i.test(e.message)) {
    console.log('Authorization was cancelled — rerun connect and approve access.');
  } else {
    throw e;
  }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Cannot pre-validate the provider's decision; inspect the callback before or catch the throw.
const params = new URL(callbackUrl).searchParams;
if (params.get('error')) {
  console.log('OAuth provider error:', params.get('error_description') || params.get('error'));
}

Type guard

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

Try / catch

try {
  await xai.connect();
} catch (err) {
  // message is error_description || error from the provider
  if (err.message.includes('access_denied')) {
    // user cancelled — prompt retry
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: During xaiOAuthService.connect(), the browser redirect lands on the loopback callback with a non-empty `error` query parameter (e.g. access_denied, unauthorized_client, server_error) because xAI's authorize endpoint rejected the request.

Common situations: User clicked 'Cancel'/'Deny' on the xAI consent screen; the xAI account lacks access to the requested scopes; the authorize URL carries a bad client_id or redirect_uri (misconfigured/reordered XAI_CONFIG or stale discovered endpoints); rate limits or a transient xAI outage producing server_error; cached browser session reusing an expired/revoked consent.

Related errors


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