chatboxai/chatbox · error · Error
Token refresh failed: ${response.status}
Error message
Token refresh failed: ${response.status} What it means
Thrown when OpenAI's refresh POST to auth.openai.com/oauth/token returns non-2xx. Note this message interpolates only response.status (not the body), even though the body is read into `text` and logged — the thrown error is less informative than the log. Common cause is an invalid/expired/revoked refresh token.
Source
Thrown at src/main/oauth/providers/openai.ts:105
async refreshToken(credentials) {
if (!credentials.refreshToken) {
throw new Error('No refresh token available')
}
const response = await fetch(TOKEN_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: credentials.refreshToken,
client_id: CLIENT_ID,
}),
})
if (!response.ok) {
const text = await response.text()
log.error('[OAuth:OpenAI] Token refresh failed:', text)
throw new Error(`Token refresh failed: ${response.status}`)
}
const data = (await response.json()) as {
access_token?: string
refresh_token?: string
expires_in?: number
}
if (!data.access_token) {
throw new Error('Token refresh response missing access_token')
}
return {
accessToken: data.access_token,
refreshToken: data.refresh_token || credentials.refreshToken,
expiresAt: typeof data.expires_in === 'number' ? Date.now() + data.expires_in * 1000 - 5 * 60 * 1000 : undefined,
extra: {
accountId: extractAccountId(data.access_token),View on GitHub (pinned to 81571269ad)
Solutions
- On 400/401, clear stored credentials and run login() again — the refresh token is dead.
- On 5xx or network error, retry once with backoff before surfacing.
- Improve the thrown error to include the body text (it is already being read) so callers can branch on the reason.
- Serialize refresh calls per account to avoid rotation races.
Example fix
// before
const text = await response.text()
log.error('[OAuth:OpenAI] Token refresh failed:', text)
throw new Error(`Token refresh failed: ${response.status}`)
// after
const text = await response.text()
log.error('[OAuth:OpenAI] Token refresh failed:', response.status, text)
if (response.status >= 500) throw new TransientError('OpenAI refresh transient')
if (response.status === 400 || response.status === 401) {
throw new ReauthRequiredError(`OpenAI refresh token invalid: ${text}`)
}
throw new Error(`Token refresh failed (${response.status}): ${text}`) Defensive patterns
Strategy: try-catch
Try / catch
try {
return await provider.refreshToken(credentials)
} catch (e) {
const msg = String(e)
if (/Token refresh failed/i.test(msg)) {
if (/\b(5\d\d|network|fetch)\b/i.test(msg)) return await provider.refreshToken(credentials)
// 400/401: refresh token invalid — clear and re-login
await clearStoredCredentials()
throw new ReauthRequiredError(msg)
}
throw e
} Prevention
- Improve the thrown error to include the response body (already read into `text`) so callers can branch on invalid_grant vs transient.
- Serialize refresh calls per account to avoid token-rotation races.
- Clear stored credentials on 4xx to avoid retrying a dead refresh token.
When it happens
Trigger: Refresh token revoked by the user at OpenAI; token expired due to inactivity; client_id mismatch; network/5xx failure; concurrent refresh invalidating the prior token.
Common situations: User disconnected the app from their OpenAI account; long idle period; a second device refreshed first; CLIENT_ID constant drifted.
Related errors
- Token refresh failed: ${error}
- Token refresh failed: ${text}
- No refresh token available
- Token refresh response missing access_token
- Token exchange failed: ${response.status}
AI-assisted analysis of chatboxai/chatbox@81571269ad (2026-08-12).
Data as JSON: /api/errors/0bd8d84e22849f96.
Report an issue: GitHub.