yikart/AiToEarn · error · AppException
ChannelPlatformApiFailed
ChannelPlatformApiFailed
Error message
ChannelPlatformApiFailed
What it means
fetchAccessToken calls RedNote's OAuth API and expects response.data.success plus a data.access_token. When the platform responds (within the 10s timeout) but reports success=false or omits access_token, this ChannelPlatformApiFailed is thrown with the platform (RedNote) and the platform's msg as reason. It signals an upstream RedNote authorization API rejection, not a local bug.
Source
Thrown at project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/rednote/offline-qr/rednote-offline-qr.service.ts:59
try {
const response = await axios.post<RedNoteAccessTokenResponse>(
this.config.accessTokenUrl,
{
app_key: this.config.appKey,
nonce,
timestamp,
signature,
},
{
headers: { 'Content-Type': 'application/json' },
timeout: 10000,
},
)
const accessToken = response.data?.data?.access_token
if (!response.data?.success || !accessToken) {
throw new AppException(ResponseCode.ChannelPlatformApiFailed, {
platform: AccountType.RedNote,
reason: response.data?.msg,
})
}
return accessToken
}
catch (error) {
if (error instanceof AppException) {
throw error
}
throw new AppException(ResponseCode.ChannelPlatformApiFailed, {
platform: AccountType.RedNote,
})
}
}
private generateNonce(length = 10): string {View on GitHub (pinned to d3aa8bea5b)
Solutions
- Read the `reason` (response.data.msg) field in the exception payload — it contains RedNote's own error message identifying the rejection cause.
- Verify the RedNote client key/secret and grant_type configured for the token request are correct and active in the RedNote open platform console.
- Ensure the authorization code being exchanged is fresh and single-use; re-run the OAuth flow to obtain a new code.
- Log the full response body once to confirm the response shape still matches response.data.data.access_token; update parsing if the platform changed its schema.
Example fix
// before
const accessToken = response.data?.data?.access_token
if (!response.data?.success || !accessToken) { throw ... }
// after
const accessToken = response.data?.data?.access_token
if (!accessToken) {
this.logger.error(`RedNote token exchange failed: ${JSON.stringify(response.data)}`)
throw new AppException(ResponseCode.ChannelPlatformApiFailed, {
platform: AccountType.RedNote,
reason: response.data?.msg ?? 'missing access_token',
})
} Defensive patterns
Strategy: try-catch
Validate before calling
// No local pre-check can fully prevent upstream rejection; verify inputs before exchange
if (!authCode) throw new Error('Missing RedNote authorization code')
if (!process.env.REDNOTE_CLIENT_KEY || !process.env.REDNOTE_CLIENT_SECRET) {
throw new Error('RedNote client credentials not configured')
} Type guard
function hasAccessToken(res: unknown): res is { success: boolean; data: { access_token: string } } {
return !!res && typeof res === 'object'
&& 'success' in res && (res as any).success === true
&& !!(res as any).data?.access_token
} Try / catch
try {
await rednoteService.accessToken(...)
} catch (e) {
if (e instanceof AppException && e.code === ResponseCode.ChannelPlatformApiFailed) {
logger.error('RedNote token exchange rejected:', e.details?.reason)
// surface re-auth requirement to user
}
} Prevention
- Keep RedNote client key/secret in env config and validate at startup.
- Always use a freshly obtained, single-use authorization code.
- Log the platform msg/reason field on every token failure.
- Monitor RedNote API changelog for response schema changes.
When it happens
Trigger: Calling accessToken/fetchAccessToken for RedNote when the upstream API returns { success: false, msg: ... } or returns 200 without data.access_token — e.g. invalid app_id/app_secret, invalid or expired auth code, revoked grant, or RedNote-side error payload.
Common situations: Wrong RedNote client credentials in env config; exchanging an already-used or expired authorization code; RedNote app not approved/whitelisted for the token endpoint; RedNote API contract change so access_token moved out of data.data.
Related errors
- ChannelAccessTokenFailed
- ChannelAccessTokenFailed
- 授权TikTok账户失败: ${error.response?.data?.error_description || e
- 交换令牌失败: ${data}
- 交换授权码失败: ${error.response?.data?.error_description || error.
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/e2f4ec3088467f9c.
Report an issue: GitHub.