decolua/9router · error · Error
"Trae callback missing refreshToken"
Error message
"Trae callback missing refreshToken"
What it means
Thrown by parseTraeCallback when no error param is present but none of the accepted refresh-token keys (refreshToken, refresh_token, RefreshToken) appear in the callback parameters. The callback succeeded from Trae's perspective but the credential this library requires is absent, so the account cannot be persisted.
Source
Thrown at src/lib/oauth/providers/trae.js:99
// 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) {
const body = JSON.stringify({
ClientID: TRAE_CONFIG.clientId,
RefreshToken: refreshToken,View on GitHub (pinned to 90b52e06ff)
Solutions
- Inspect the full callback URL/query string and confirm which parameters Trae actually returned.
- If Trae renamed the field, add the new key name to the pick() list (refresh_token variants) in parseTraeCallback.
- Re-run the login flow and paste the complete, unmodified callback URL.
- Check any proxy/redirect layer for query-param stripping.
Example fix
// before const refreshToken = pick(["refreshToken", "refresh_token", "RefreshToken"]); // after const refreshToken = pick(["refreshToken", "refresh_token", "RefreshToken", "refreshTokenKey"]); // add renamed key
Defensive patterns
Strategy: validation
Validate before calling
const params = new URLSearchParams(callbackUrl.split('?')[1] || '');
const hasRefresh = ['refreshToken', 'refresh_token', 'RefreshToken'].some(k => params.get(k)?.trim());
if (!hasRefresh) throw new Error('Callback has no refresh token; re-run Trae login'); Type guard
const isNonEmptyString = (v) => typeof v === 'string' && v.trim().length > 0;
Try / catch
try {
const creds = parseTraeCallback(callbackUrl);
} catch (e) {
if (e.message === 'Trae callback missing refreshToken') {
// log raw query params; re-run login or update accepted key names
} else throw e;
} Prevention
- Log the raw callback query string (minus secrets) to catch provider-side param renames quickly.
- Never hand-edit or truncate the callback URL when pasting it.
- Check redirect chains/proxies for query-param stripping.
When it happens
Trigger: Trae redirects back with a success payload that lacks any refresh-token field: provider changed the callback parameter names, callback was truncated/modified by a redirect chain, or a partial/malformed callback URL was pasted manually.
Common situations: Trae renames callback params in a new version; a middleware/reverse proxy strips query params; the user hand-edited the callback URL; copying the URL dropped part of the query string.
Related errors
- "Trae callback missing loginHost"
- No Codex access token available. Please re-authorize the con
- "Missing Kimchi token"
- `Trae GetLoginGuidance failed: ${lastErr}`
- desc ? `Trae auth failed: ${err} (${desc})` : `Trae auth fai
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/1c6c33e3f45728f0.
Report an issue: GitHub.