musistudio/claude-code-router · error · Error
Kimi CLI refresh token was not found.
Error message
Kimi CLI refresh token was not found.
What it means
refreshKimiAuth requires a refresh token to mint a new access token, but the stored KimiTokenSet has an empty/absent refreshToken. Without it the OAuth refresh grant cannot even be attempted, so the error is thrown before any network call.
Source
Thrown at packages/core/src/agents/local-providers/kimi.ts:399
return {
key: configured.oauthKey,
...(configured.oauthHost ? { oauthHost: configured.oauthHost } : {})
};
}
function findKimiOauthProvider(reference?: KimiOauthReference): KimiConfiguredProvider | undefined {
const configured = readKimiConfiguredProviders().filter((item) => Boolean(item.oauthKey && !item.apiKey));
const key = reference?.key?.trim();
if (!key) return configured[0];
const oauthHost = reference?.oauthHost?.trim().replace(/\/+$/, "");
return configured.find((item) =>
item.oauthKey === key && (!oauthHost || item.oauthHost?.replace(/\/+$/, "") === oauthHost)
) ?? configured.find((item) => item.oauthKey === key);
}
async function refreshKimiAuth(auth: KimiTokenSet): Promise<KimiTokenSet> {
if (!auth.refreshToken) {
throw new Error("Kimi CLI refresh token was not found.");
}
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), kimiOauthRefreshTimeoutMs);
const oauthHost = (auth.oauthHost || kimiOauthHost).replace(/\/+$/, "");
try {
const response = await fetchWithSystemProxy(`${oauthHost}/api/oauth/token`, {
body: new URLSearchParams({
client_id: kimiOauthClientId,
grant_type: "refresh_token",
refresh_token: auth.refreshToken
}).toString(),
headers: {
...withoutHeader(kimiIdentityHeaders(), "user-agent"),
accept: "application/json",
"content-type": "application/x-www-form-urlencoded"
},
method: "POST",
signal: controller.signalView on GitHub (pinned to 99f24806c6)
Solutions
- Re-run the full kimi OAuth login to obtain a token set that includes a refresh token
- Inspect the stored credentials file to confirm refresh_token is present and non-empty
- If the provider no longer issues refresh tokens, fall back to API key authentication
- Ensure the login flow requests offline access scope
Defensive patterns
Strategy: validation
Validate before calling
const auth = await resolveKimiAuth(ref).catch(() => undefined);
if (auth && kimiAccessTokenExpired(auth) && !auth.refreshToken) {
await kimiLogin(); // cannot refresh, must re-auth
} Type guard
function canRefreshKimi(auth: KimiTokenSet): boolean {
return typeof auth.refreshToken === 'string' && auth.refreshToken.length > 0;
} Try / catch
catch (e) {
if (e instanceof Error && e.message === 'Kimi CLI refresh token was not found.') {
await kimiLogin(); // no retry path exists
}
} Prevention
- Require offline-access scope at login so refresh tokens are issued
- Validate token sets contain refreshToken before persisting
- Fall back to API key auth when no refresh token is available
When it happens
Trigger: resolveKimiAuth decides the access token is expired and calls refreshKimiAuth, but the persisted token set was created from a flow that never issued a refresh token, or the field was lost/cleared in config.
Common situations: API-key-based setups that later switched to OAuth with a partial token set; config migration dropped the refresh_token field; the provider issued only short-lived tokens without offline_access scope.
Related errors
- Kimi CLI OAuth token refresh returned HTTP ${response.status
- Kimi CLI credential was not found or is expired.
- Kimi CLI OAuth token refresh returned an incomplete token re
- Kimi CLI OAuth token refresh timed out after ${kimiOauthRefr
- Grok CLI OAuth token refresh did not return an access token.
AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27).
Data as JSON: /api/errors/bb5a50d22ab3cea8.
Report an issue: GitHub.