{"record":{"id":"b5e9e06048d93309","repo":"chatboxai/chatbox","slug":"token-refresh-failed-text","errorCode":null,"errorMessage":"Token refresh failed: ${text}","messagePattern":"Token refresh failed: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/oauth/providers/minimax.ts","lineNumber":217,"sourceCode":"      }\n\n      const response = await fetch(`${config.baseUrl}/oauth/token`, {\n        method: 'POST',\n        headers: {\n          Accept: 'application/json',\n          'Content-Type': 'application/x-www-form-urlencoded',\n        },\n        body: new URLSearchParams({\n          grant_type: 'refresh_token',\n          client_id: MINIMAX_CLIENT_ID,\n          refresh_token: credentials.refreshToken,\n        }).toString(),\n      })\n\n      const text = await response.text()\n      if (!response.ok) {\n        log.error(`[OAuth:${config.name}] Token refresh failed:`, text)\n        throw new Error(`Token refresh failed: ${text}`)\n      }\n\n      const payload = JSON.parse(text || '{}') as {\n        status?: string\n        access_token?: string\n        refresh_token?: string\n        expired_in?: number\n        base_resp?: { status_msg?: string }\n      }\n\n      if (payload.status !== 'success' || !payload.access_token) {\n        throw new Error(`Token refresh failed: ${payload.base_resp?.status_msg || text}`)\n      }\n\n      return {\n        accessToken: payload.access_token,\n        refreshToken: payload.refresh_token || credentials.refreshToken,\n        expiresAt: toExpiresAt(payload.expired_in),","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/chatboxai/chatbox/blob/81571269addb6bafb589a920b2883f1e1e084fd1/src/main/oauth/providers/minimax.ts#L199-L235","documentation":"Thrown by MiniMax's refreshToken() when the POST to {baseUrl}/oauth/token returns non-2xx. The raw response text is interpolated and logged. This is the transport-level refresh failure; a separate guard (error 72) handles the case where HTTP is 200 but the business status is not 'success'.","triggerScenarios":"Refresh token revoked or expired (MiniMax returns 4xx); wrong baseUrl for the provider variant; MINIMAX_CLIENT_ID mismatch; network failure / 5xx; concurrent refresh calls invalidating the token.","commonSituations":"Long-idle user whose MiniMax grant expired; selected CN provider but global endpoint was hit (or vice-versa); a parallel refresh on another device rotated the token.","solutions":["On 4xx with revocation language, clear stored credentials and trigger an interactive startDeviceFlow() login.","On 5xx or network error, retry once with backoff.","Verify baseUrl matches the provider variant (api.minimax.io vs api.minimaxi.com).","Serialize refresh calls per account to avoid rotation races."],"exampleFix":"// before\nif (!response.ok) {\n  const text = await response.text()\n  throw new Error(`Token refresh failed: ${text}`)\n}\n\n// after\nif (!response.ok) {\n  const text = await response.text()\n  if (response.status >= 500) throw new TransientError('MiniMax refresh transient')\n  if (response.status === 400 || response.status === 401) {\n    throw new ReauthRequiredError('MiniMax refresh token invalid — re-login required')\n  }\n  throw new Error(`Token refresh failed (${response.status}): ${text}`)\n}","handlingStrategy":"try-catch","validationCode":"function assertMiniMaxVariantForRefresh(providerId: string, baseUrl: string) {\n  if (providerId === 'minimax' && !baseUrl.includes('api.minimax.io')) throw new Error('Global MiniMax must use api.minimax.io')\n  if (providerId === 'minimax-cn' && !baseUrl.includes('api.minimaxi.com')) throw new Error('CN MiniMax must use api.minimaxi.com')\n}","typeGuard":null,"tryCatchPattern":"try {\n  return await provider.refreshToken(credentials)\n} catch (e) {\n  const msg = String(e)\n  if (/Token refresh failed/i.test(msg)) {\n  if (/5\\d\\d|network|fetch/i.test(msg)) return await provider.refreshToken(credentials)\n  // 4xx: refresh token dead — force re-login\n  await clearStoredCredentials()\n  throw new ReauthRequiredError(msg)\n  }\n  throw e\n}","preventionTips":["Match baseUrl to the provider variant on refresh too (not just at startDeviceFlow).","Serialize refresh calls per account to avoid rotation races.","Clear stored credentials on 4xx so a dead token is not retried forever."],"tags":["oauth","network","minimax","refresh-token"],"backgroundTag":null,"analyzedSha":"81571269addb6bafb589a920b2883f1e1e084fd1","analyzedAt":"2026-08-12T21:51:44.981Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}