{"record":{"id":"3a1538331d58c553","repo":"decolua/9router","slug":"desc-trae-auth-failed-err-desc-tra","errorCode":null,"errorMessage":"desc ? `Trae auth failed: ${err} (${desc})` : `Trae auth failed: ${err}`","messagePattern":"desc \\? `Trae auth failed: (.+?) \\((.+?)\\)` : `Trae auth failed: (.+?)`","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/lib/oauth/providers/trae.js","lineNumber":96,"sourceCode":"  return url.toString();\n}\n\n// Parse the Trae OAuth callback (query string or full URL).\n// Expected: ?isRedirect=true&refreshToken=...&loginHost=...[&x-cloudide-token=...]\nfunction parseTraeCallback(raw) {\n  const text = String(raw || \"\").trim();\n  let queryStr = text;\n  if (text.includes(\"?\")) queryStr = text.slice(text.indexOf(\"?\") + 1);\n  if (text.startsWith(\"#\")) queryStr = text.slice(1);\n  const params = Object.fromEntries(new URLSearchParams(queryStr));\n  const pick = (keys) => {\n    for (const k of keys) { const v = params[k]; if (v && String(v).trim()) return String(v).trim(); }\n    return null;\n  };\n  const err = pick([\"error\", \"error_code\", \"errorCode\"]);\n  if (err) {\n    const desc = pick([\"error_description\", \"error_desc\", \"message\"]);\n    throw new Error(desc ? `Trae auth failed: ${err} (${desc})` : `Trae auth failed: ${err}`);\n  }\n  const refreshToken = pick([\"refreshToken\", \"refresh_token\", \"RefreshToken\"]);\n  if (!refreshToken) throw new Error(\"Trae callback missing refreshToken\");\n  const loginHost = pick([\"loginHost\", \"login_host\", \"LoginHost\", \"host\", \"consoleHost\"]);\n  if (!loginHost) throw new Error(\"Trae callback missing loginHost\");\n  const cloudideToken = pick([\"x-cloudide-token\", \"xCloudideToken\", \"accessToken\", \"access_token\", \"token\"]);\n  return { refreshToken, loginHost, cloudideToken };\n}\n\n// Allowed API origins for ExchangeToken/GetUserInfo — hardcoded HTTPS allowlist only.\n// loginHost from the callback is intentionally NOT honored (SSRF guard: a callback\n// attacker could otherwise point this at internal hosts/cloud metadata).\nfunction traeApiOrigins() {\n  return [...TRAE_CONFIG.apiOrigins];\n}\n\n// POST ExchangeToken {ClientID, RefreshToken, ClientSecret, UserID} → {Result:{AccessToken,RefreshToken,ExpiresAt}}\nasync function fetchTraeExchangeToken(refreshToken, cloudideToken) {","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/lib/oauth/providers/trae.js#L78-L114","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read the embedded err/desc values — they describe Trae's specific failure (access_denied, expired session, etc.).","Restart the login flow from scratch to get a fresh loginTraceId and retry sign-in.","If desc indicates denial, have the user complete consent instead of closing the browser window.","If the errorCode is unknown, check Trae docs/support for its current meaning."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const params = new URLSearchParams(callbackUrl.split('?')[1] || '');\nconst hasError = ['error', 'error_code', 'errorCode'].some(k => params.get(k));\nif (hasError) throw new Error('Trae sign-in failed: ' + (params.get('error_description') || params.get('error')));","typeGuard":null,"tryCatchPattern":"try {\n  const creds = parseTraeCallback(callbackUrl);\n} catch (e) {\n  if (e.message.startsWith('Trae auth failed:')) {\n    // surface err/desc to user; restart the login flow for a fresh attempt\n  } else throw e;\n}","preventionTips":["Instruct users not to close the browser window before completing consent.","Always start a fresh login flow rather than replaying an old callback URL.","Parse the callback early and show err/desc directly to the user for diagnosis."],"tags":["oauth","oauth-callback","auth-denied"],"backgroundTag":"oauth-callback-error","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}