decolua/9router · error · Error

desc ? `Trae auth failed: ${err} (${desc})` : `Trae auth fai

Error message

desc ? `Trae auth failed: ${err} (${desc})` : `Trae auth failed: ${err}`

What it means

Thrown by parseTraeCallback when the OAuth callback URL/query parameters contain an error indicator — error, error_code, or errorCode — meaning Trae's sign-in failed on their side. An optional error_description/error_desc/message is appended in parentheses. No tokens are extracted when this fires.

Source

Thrown at src/lib/oauth/providers/trae.js:96

  return url.toString();
}

// Parse the Trae OAuth callback (query string or full URL).
// Expected: ?isRedirect=true&refreshToken=...&loginHost=...[&x-cloudide-token=...]
function parseTraeCallback(raw) {
  const text = String(raw || "").trim();
  let queryStr = text;
  if (text.includes("?")) queryStr = text.slice(text.indexOf("?") + 1);
  if (text.startsWith("#")) queryStr = text.slice(1);
  const params = Object.fromEntries(new URLSearchParams(queryStr));
  const pick = (keys) => {
    for (const k of keys) { const v = params[k]; if (v && String(v).trim()) return String(v).trim(); }
    return null;
  };
  const err = pick(["error", "error_code", "errorCode"]);
  if (err) {
    const desc = pick(["error_description", "error_desc", "message"]);
    throw new Error(desc ? `Trae auth failed: ${err} (${desc})` : `Trae auth failed: ${err}`);
  }
  const refreshToken = pick(["refreshToken", "refresh_token", "RefreshToken"]);
  if (!refreshToken) throw new Error("Trae callback missing refreshToken");
  const loginHost = pick(["loginHost", "login_host", "LoginHost", "host", "consoleHost"]);
  if (!loginHost) throw new Error("Trae callback missing loginHost");
  const cloudideToken = pick(["x-cloudide-token", "xCloudideToken", "accessToken", "access_token", "token"]);
  return { refreshToken, loginHost, cloudideToken };
}

// Allowed API origins for ExchangeToken/GetUserInfo — hardcoded HTTPS allowlist only.
// loginHost from the callback is intentionally NOT honored (SSRF guard: a callback
// attacker could otherwise point this at internal hosts/cloud metadata).
function traeApiOrigins() {
  return [...TRAE_CONFIG.apiOrigins];
}

// POST ExchangeToken {ClientID, RefreshToken, ClientSecret, UserID} → {Result:{AccessToken,RefreshToken,ExpiresAt}}
async function fetchTraeExchangeToken(refreshToken, cloudideToken) {

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Read the embedded err/desc values — they describe Trae's specific failure (access_denied, expired session, etc.).
  2. Restart the login flow from scratch to get a fresh loginTraceId and retry sign-in.
  3. If desc indicates denial, have the user complete consent instead of closing the browser window.
  4. If the errorCode is unknown, check Trae docs/support for its current meaning.
Defensive patterns

Strategy: try-catch

Validate before calling

const params = new URLSearchParams(callbackUrl.split('?')[1] || '');
const hasError = ['error', 'error_code', 'errorCode'].some(k => params.get(k));
if (hasError) throw new Error('Trae sign-in failed: ' + (params.get('error_description') || params.get('error')));

Try / catch

try {
  const creds = parseTraeCallback(callbackUrl);
} catch (e) {
  if (e.message.startsWith('Trae auth failed:')) {
    // surface err/desc to user; restart the login flow for a fresh attempt
  } else throw e;
}

Prevention

When it happens

Trigger: The browser redirect back to the callback carries error params: user denied consent, Trae login session expired mid-flow, invalid state, account restriction, or Trae returned an errorCode for any sign-in failure.

Common situations: User cancelled the consent screen; SSO/2FA failed at Trae; Trae reported an app-level errorCode after a policy change; stale login attempt reused after expiration.

Related errors


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