chatboxai/chatbox · error · Error

Token refresh failed: ${payload.base_resp?.status_msg || tex

Error message

Token refresh failed: ${payload.base_resp?.status_msg || text}

What it means

Thrown by MiniMax's refreshToken() when the HTTP response was 2xx but payload.status !== 'success' or payload.access_token is missing. MiniMax returns 200 with a business status field, so this guard catches application-level refresh failures that the HTTP check missed. The message prefers base_resp.status_msg (human-readable MiniMax reason) and falls back to the raw text.

Source

Thrown at src/main/oauth/providers/minimax.ts:229

        }).toString(),
      })

      const text = await response.text()
      if (!response.ok) {
        log.error(`[OAuth:${config.name}] Token refresh failed:`, text)
        throw new Error(`Token refresh failed: ${text}`)
      }

      const payload = JSON.parse(text || '{}') as {
        status?: string
        access_token?: string
        refresh_token?: string
        expired_in?: number
        base_resp?: { status_msg?: string }
      }

      if (payload.status !== 'success' || !payload.access_token) {
        throw new Error(`Token refresh failed: ${payload.base_resp?.status_msg || text}`)
      }

      return {
        accessToken: payload.access_token,
        refreshToken: payload.refresh_token || credentials.refreshToken,
        expiresAt: toExpiresAt(payload.expired_in),
      }
    },
  }

  return provider
}

export const minimaxOAuthProvider = createMiniMaxOAuthProvider({
  providerId: 'minimax',
  name: 'MiniMax Global',
  baseUrl: 'https://api.minimax.io',
})

View on GitHub (pinned to 81571269ad)

Solutions

  1. Read base_resp.status_msg — it carries MiniMax's specific reason; treat account/quota messages as requiring re-auth or user action.
  2. If the response shape changed (status renamed), update the parse to match the current MiniMax contract.
  3. On business-level 'fail', clear stored credentials and prompt an interactive login rather than retrying the same refresh token.

Example fix

// before
if (payload.status !== 'success' || !payload.access_token) {
  throw new Error(`Token refresh failed: ${payload.base_resp?.status_msg || text}`)
}

// after
if (payload.status !== 'success' || !payload.access_token) {
  const reason = payload.base_resp?.status_msg || text
  log.error('[OAuth:MiniMax] business refresh failure', reason)
  if (/invalid|expired|revok/i.test(reason)) throw new ReauthRequiredError(reason)
  throw new Error(`Token refresh failed: ${reason}`)
}
Defensive patterns

Strategy: try-catch

Type guard

function isMiniMaxBusinessFailure(body: unknown): body is { status: string; base_resp?: { status_msg?: string } } {
  return typeof body === 'object' && body !== null && (body as any).status !== 'success'
}

Try / catch

try {
  return await provider.refreshToken(credentials)
} catch (e) {
  const msg = String(e)
  if (/invalid|expired|revok|suspend|quota/i.test(msg)) {
  await clearStoredCredentials()
  throw new ReauthRequiredError(msg)
  }
  // contract drift: log and surface, do not retry blindly
  log.error('MiniMax business refresh failure', msg)
  throw e
}

Prevention

When it happens

Trigger: MiniMax returns 200 with status='fail' or a non-zero base_resp.status_code; access_token field absent despite 200; response shape changed and status field is now named differently; refresh token was accepted at transport but rejected at business layer (e.g. quota, account suspended).

Common situations: MiniMax API contract drift (status field renamed); account throttled or suspended returning 200 with an error status_msg; partial response from a load balancer.

Related errors


AI-assisted analysis of chatboxai/chatbox@81571269ad (2026-08-12). Data as JSON: /api/errors/1094cc085e3e6414. Report an issue: GitHub.