CherryHQ/cherry-studio · error · Error
Failed to get access token: HTTP ${response.status}
Error message
Failed to get access token: HTTP ${response.status} What it means
Thrown when the QQ AppAccessToken endpoint (https://bots.qq.com/app/getAppAccessToken) returns a non-2xx status. The message embeds response.status only; the body is not read. This token is mandatory for subsequent QQ API calls (Authorization: QQBot <token>).
Source
Thrown at src/main/ai/channels/adapters/qq/QqAdapter.ts:171
}
private async getAccessToken(): Promise<string> {
// Check cache
if (this.tokenCache && Date.now() < this.tokenCache.expiresAt - 60000) {
return this.tokenCache.accessToken
}
const response = await net.fetch('https://bots.qq.com/app/getAppAccessToken', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
appId: this.appId,
clientSecret: this.clientSecret
})
})
if (!response.ok) {
throw new Error(`Failed to get access token: HTTP ${response.status}`)
}
const data = (await response.json()) as { access_token?: string; expires_in?: number }
if (!data.access_token || !data.expires_in) {
const errorText = JSON.stringify(data)
throw new Error(`Invalid token response from QQ API: ${errorText}`)
}
this.tokenCache = {
accessToken: data.access_token,
expiresAt: Date.now() + data.expires_in * 1000
}
return data.access_token
}
private async apiRequest(
endpoint: string,View on GitHub (pinned to 726446b54c)
Solutions
- Confirm appId/clientSecret are correct and match a QQ bot in the q.qq.com console.
- For 5xx or rate-limit status, back off and retry the token request.
- Read the response body for QQ's error detail to disambiguate 401 (bad creds) vs 429 (rate limit).
- Ensure the host can reach bots.qq.com without TLS interception.
Example fix
// before
if (!response.ok) {
throw new Error(`Failed to get access token: HTTP ${response.status}`)
}
// after — include body for diagnosis and retry on transient 5xx
if (!response.ok) {
const detail = await response.text().catch(() => '')
if (response.status >= 500) {
await new Promise((r) => setTimeout(r, 1000))
return this.fetchAccessToken() // bounded retry
}
throw new Error(`Failed to get access token: HTTP ${response.status} - ${detail}`)
} Defensive patterns
Strategy: retry
Validate before calling
// Pre-flight: token endpoint reachable and credentials present.
function qqCanFetchToken(appId?: string, clientSecret?: string): boolean {
return Boolean(appId?.trim() && clientSecret?.trim())
} Type guard
function isQqTokenHttpError(e: unknown): e is Error {
return e instanceof Error && /^Failed to get access token: HTTP \d+$/.test(e.message)
} Try / catch
try {
await qq.connect()
} catch (e) {
if (isQqTokenHttpError(e)) {
const status = Number(/HTTP (\d+)/.exec(e.message)?.[1] ?? 0)
if (status >= 500) return retryConnect()
notifyUser('QQ credentials rejected or token endpoint down')
return
}
throw e
} Prevention
- Confirm appId/clientSecret from the q.qq.com console.
- Back off on 5xx/429; surface 4xx as a credentials problem.
- Ensure network reachability to bots.qq.com without TLS interception.
When it happens
Trigger: net.fetch POST to getAppAccessToken with {appId, clientSecret} returns response.ok === false; the guard throws HTTP <status> before parsing JSON.
Common situations: Wrong appId/clientSecret (QQ returns 4xx), QQ service degradation (5xx), network/proxy returning an error page, or rate limiting on the token endpoint.
Related errors
- Discord API error ${url}: HTTP ${response.status} - ${errorT
- Invalid token response from QQ API: ${errorText}
- QQ API request failed ${endpoint}: HTTP ${response.status} -
- Failed to get gateway URL: HTTP ${response.status} - ${error
- Brave API error: ${response.status} ${response.statusText}\n
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/931263eaf00a8355.
Report an issue: GitHub.