decolua/9router · error
Failed to save tokens
Error message
Failed to save tokens
What it means
Thrown by IFlowService.saveTokens() when the POST of the exchanged tokens and user profile to the 9Router server endpoint `${server}/api/cli/providers/iflow` returns non-OK. The CLI reads the server's JSON `error` field; this fallback fires when the server gave no specific error. GitHub auth has succeeded at this point — the failure is purely in persisting the connection server-side.
Source
Thrown at src/lib/oauth/services/iflow.js:116
const response = await fetch(`${server}/api/cli/providers/iflow`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
"X-User-Id": userId,
},
body: JSON.stringify({
accessToken: tokens.access_token,
refreshToken: tokens.refresh_token,
expiresIn: tokens.expires_in,
apiKey: userInfo.apiKey,
email: userInfo.email || userInfo.phone,
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || "Failed to save tokens");
}
return await response.json();
}
/**
* Complete iFlow OAuth flow
*/
async connect() {
const spinner = createSpinner("Starting iFlow OAuth...").start();
try {
spinner.text = "Starting local server...";
// Start local server for callback
let callbackParams = null;
const { port, close } = await startLocalServer((params) => {
callbackParams = params;View on GitHub (pinned to 90b52e06ff)
Solutions
- Verify the server is reachable (`curl ${server}/api/health`) and the URL config is correct.
- Re-login to the dashboard to refresh the Bearer token used by getServerCredentials().
- Ensure CLI and dashboard versions match so /api/cli/providers/iflow exists.
- Check server logs for the concrete rejection (validation, DB, auth).
- Retry — transient 5xx may pass on a second attempt.
Example fix
// before
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || "Failed to save tokens");
}
// after
if (!response.ok) {
const body = await response.text();
let msg; try { msg = JSON.parse(body).error; } catch {}
throw new Error(msg || `Failed to save tokens (HTTP ${response.status}): ${body.slice(0, 200)}`);
} Defensive patterns
Strategy: try-catch
Validate before calling
// Validate server credentials and required payload before the upload
const { server, token, userId } = getServerCredentials();
if (!server || !token) throw new Error("Missing server credentials — log in to the dashboard first");
if (!tokens.access_token || !userInfo.apiKey) throw new Error("Missing accessToken/apiKey required by the iflow provider endpoint"); Type guard
function hasServerError(data) {
return data !== null && typeof data === "object" && typeof data.error === "string";
} Try / catch
try {
await iflowService.saveTokens(tokens, userInfo);
} catch (err) {
if (/Failed to save tokens/.test(err.message) || err.message === "Failed to save tokens") {
console.error("Server rejected the iflow connection — check server reachability, JWT freshness, and server logs.", err.message);
} else { throw err; }
} Prevention
- Confirm server/URL/token config before starting the OAuth flow.
- Refresh the dashboard JWT when expired — 401s surface as this error.
- Match CLI and dashboard versions so the /api/cli/providers/iflow route exists.
- Include all required payload fields (accessToken, refreshToken, apiKey, email) to avoid 400s.
When it happens
Trigger: saveTokens(tokens, userInfo) hits a server that returns 401 (expired Bearer token / wrong X-User-Id), 404 (route missing — CLI/server version mismatch), 400 (validation rejected e.g. missing apiKey), or 500 with a body lacking `error`.
Common situations: Stale JWT after server restart/JWT_SECRET rotation; wrong server URL in config; dashboard version older than the CLI expecting the iflow provider route; server DB failure returning an empty error body.
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
- Failed to connect to server
- Failed to save tokens
- loadCodeAssist failed: HTTP ${response.status} ${errorText.s
- onboardUser HTTP ${response.status}: ${errorText.slice(0, 20
- Failed to save mappings
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/c34470662f6bd288.
Report an issue: GitHub.