{"record":{"id":"66b5789bb79e942e","repo":"openclaw/openclaw","slug":"chutes-oauth-credential-is-missing-refresh-token","errorCode":null,"errorMessage":"Chutes OAuth credential is missing refresh token","messagePattern":"Chutes OAuth credential is missing refresh token","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"extensions/chutes/oauth.ts","lineNumber":240,"sourceCode":"  }\n  return {\n    access: token.access,\n    refresh: token.refresh,\n    expires: token.expires,\n    email: info?.username,\n    accountId: info?.sub,\n    clientId: params.app.clientId,\n  } as ChutesStoredOAuth;\n}\n\n/** Refreshes a stored Chutes OAuth credential through the provider token endpoint. */\nexport async function refreshChutesOAuthCredential(\n  credential: OAuthCredential,\n  options: { fetchFn?: typeof fetch; now?: number } = {},\n): Promise<OAuthCredential> {\n  const refreshToken = normalizeOptionalString(credential.refresh);\n  if (!refreshToken) {\n    throw new Error(\"Chutes OAuth credential is missing refresh token\");\n  }\n\n  const clientId = normalizeOptionalString(credential.clientId ?? process.env.CHUTES_CLIENT_ID);\n  if (!clientId) {\n    throw new Error(\"Missing CHUTES_CLIENT_ID for Chutes OAuth refresh (set env var or re-auth).\");\n  }\n  const clientSecret = normalizeOptionalString(process.env.CHUTES_CLIENT_SECRET);\n  const body = new URLSearchParams({\n    grant_type: \"refresh_token\",\n    client_id: clientId,\n    refresh_token: refreshToken,\n  });\n  if (clientSecret) {\n    body.set(\"client_secret\", clientSecret);\n  }\n\n  const token = await requestChutesTokenGrant({\n    body,","sourceCodeStart":222,"sourceCodeEnd":258,"githubUrl":"https://github.com/openclaw/openclaw/blob/01804a75319da4b69c9ab98ceaa30477e22b8c0b/extensions/chutes/oauth.ts#L222-L258","documentation":"Thrown by refreshChutesOAuthCredential when the stored OAuthCredential's refresh field is empty or absent after normalization. This function is called to renew an expired access token; without a refresh_token it cannot perform the grant. This indicates the stored credential is incomplete or corrupted — either it was never granted a refresh token, or it was lost during storage/migration.","triggerScenarios":"A stored Chutes credential that was created by an older flow that did not persist the refresh token. Credential corruption in the auth-profiles store. Manual credential import that omitted the refresh field. A prior token exchange that did not return a refresh token but was stored anyway (older plugin version before the check at line 645 was added).","commonSituations":"Upgrading from an older OpenClaw version that stored Chutes credentials differently. Importing credentials from another tool. Storage migration that dropped fields. Corrupt auth-profiles.json after a crash.","solutions":["Re-run the Chutes OAuth onboarding flow to obtain a fresh credential with a refresh token","Inspect the stored credential (auth-profiles.json for the agent) to confirm the refresh field is missing","If this affects many agents, check whether a migration was supposed to handle old credentials"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"function hasValidRefreshCredential(cred: OAuthCredential): boolean {\n  return typeof cred.refresh === \"string\" && cred.refresh.trim().length > 0;\n}\n// Before calling refreshChutesOAuthCredential\nif (!hasValidRefreshCredential(storedCred)) {\n  await reauthenticateChutes(); // trigger fresh onboarding\n  return;\n}","typeGuard":"function hasValidRefreshCredential(cred: OAuthCredential): cred is OAuthCredential & { refresh: string } {\n  return typeof cred.refresh === \"string\" && cred.refresh.trim().length > 0;\n}","tryCatchPattern":"try {\n  const refreshed = await refreshChutesOAuthCredential(credential);\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"missing refresh token\")) {\n    // Credential is incomplete; prompt re-authentication\n    await triggerChutesReauth(agentId);\n  } else { throw e; }\n}","preventionTips":["Validate stored credentials have refresh_token after onboarding","Run 'openclaw doctor' after upgrades to detect credential issues","Keep credential storage migrations tested"],"tags":["oauth","refresh-token","credential-storage","migration"],"backgroundTag":null,"analyzedSha":"01804a75319da4b69c9ab98ceaa30477e22b8c0b","analyzedAt":"2026-08-12T04:37:58.197Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}