decolua/9router · error · Error
Failed to get user info: ${error}
Error message
Failed to get user info: ${error} What it means
Thrown by IFlowService.getUserInfo() when the iFlow user-info endpoint returns a non-OK HTTP status. The raw response text is embedded in the message. This happens after a successful token exchange, so the access token exists but the user-info call rejected it or the endpoint itself failed.
Source
Thrown at src/lib/oauth/services/iflow.js:80
return await response.json();
}
/**
* Get user info from iFlow
*/
async getUserInfo(accessToken) {
const response = await fetch(
`${this.config.userInfoUrl}?accessToken=${encodeURIComponent(accessToken)}`,
{
headers: {
Accept: "application/json",
},
}
);
if (!response.ok) {
const error = await response.text();
throw new Error(`Failed to get user info: ${error}`);
}
const result = await response.json();
if (!result.success) {
throw new Error("Failed to get user info");
}
return result.data;
}
/**
* Save iFlow tokens to server
*/
async saveTokens(tokens, userInfo) {
const { server, token, userId } = getServerCredentials();
const response = await fetch(`${server}/api/cli/providers/iflow`, {View on GitHub (pinned to 90b52e06ff)
Solutions
- Inspect the embedded body in the message for the actual status/cause (401/403 → token problem, 404 → endpoint changed).
- Verify the access token from exchangeCode is the one iFlow expects (access_token vs apikey field mix-up).
- Check IFLOW_CONFIG.userInfoUrl against current iFlow API docs — the endpoint may have moved.
- Retry after a short wait if the message indicates 429/5xx.
- Restart the full connect() flow to obtain a fresh token.
Example fix
// before
if (!response.ok) {
const error = await response.text();
throw new Error(`Failed to get user info: ${error}`);
}
// after
if (!response.ok) {
const error = await response.text();
throw new Error(`Failed to get user info (HTTP ${response.status}): ${error}`);
} Defensive patterns
Strategy: try-catch
Validate before calling
// Check the token looks usable before calling user info
if (!accessToken || typeof accessToken !== "string" || accessToken.length < 10) {
throw new Error("Refusing to call getUserInfo with a missing/short access token");
} Try / catch
try {
const userInfo = await iflowService.getUserInfo(tokens.access_token);
} catch (err) {
if (/Failed to get user info/.test(err.message)) {
if (/401|403|Unauthorized|Forbidden/i.test(err.message)) {
console.error("Token rejected for user info — obtain a fresh token via connect().");
} else if (/404|Not Found/i.test(err.message)) {
console.error("userInfoUrl changed — update IFLOW_CONFIG.userInfoUrl.");
}
} else { throw err; }
} Prevention
- Always pass tokens.access_token from the exchange response, not another field.
- Keep IFLOW_CONFIG.userInfoUrl current with iFlow's API.
- Handle 429/5xx with a short backoff retry before failing.
- Test from the same network the CLI will run on (proxies/VPNs alter responses).
When it happens
Trigger: getUserInfo(accessToken) is called and the server answers 401/403 (token invalid, expired, or lacking scope for user info), 404 (userInfoUrl changed), or 5xx (upstream outage); also when a proxy intercepts and returns an HTML error page.
Common situations: iFlow access token already invalid despite the exchange succeeding (clock skew, token type mismatch); userInfoUrl in IFLOW_CONFIG outdated after an API change; corporate proxy blocking the endpoint; rate limiting returning 429.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- loadCodeAssist failed: HTTP ${response.status} ${errorText.s
- onboardUser HTTP ${response.status}: ${errorText.slice(0, 20
- `Failed to fetch user info: ${errorText}`
- Failed to save tokens
- Failed to get device code: ${error}
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/1796121ca973b3fd.
Report an issue: GitHub.