yikart/AiToEarn · error · AppException
ChannelAccessTokenFailed
ChannelAccessTokenFailed
Error message
ResponseCode.ChannelAccessTokenFailed
What it means
During the Douyin mini-app callback exchange, exchangeMiniAppCallback calls code2Session(callback.token) and requires a session containing an openid. If the session is null or has no openid, the app cannot identify the Douyin user, so it throws ChannelAccessTokenFailed — the code-to-session exchange did not yield a usable access identity.
Source
Thrown at project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/douyin/douyin-auth.provider.ts:151
raw: {
openId: userInfo.openId,
unionId: userInfo.unionId,
nickname: userInfo.nickname,
city: userInfo.city,
province: userInfo.province,
country: userInfo.country,
eAccountRole: userInfo.eAccountRole,
},
}
}
private async exchangeMiniAppCallback(
input: AuthCallbackInput,
callback: DouyinMiniAppCallback,
): Promise<CredentialResult> {
const sessionInfo = await this.douyinMiniAppService.code2Session(callback.token)
if (!sessionInfo?.openid) {
throw new AppException(ResponseCode.ChannelAccessTokenFailed)
}
const openId = sessionInfo.openid
const unionId = sessionInfo.unionid
if (this.config.authType !== AuthType.QrCode) {
throw new AppException(ResponseCode.ChannelAuthorizationFailed)
}
if (!callback.tickets) {
throw new AppException(ResponseCode.ChannelAuthorizationFailed)
}
const userDataTicket = callback.tickets[DOUYIN_MINIAPP_USER_DATA_SCOPE]
const videoBindTicket = callback.tickets[DOUYIN_MINIAPP_VIDEO_BIND_SCOPE]
const homepageCredential = await this.douyinMiniAppService.getUserAccessToken(userDataTicket)
const videoCredential = userDataTicket === videoBindTicket
? homepageCredential
: await this.douyinMiniAppService.getUserAccessToken(videoBindTicket)
View on GitHub (pinned to d3aa8bea5b)
Solutions
- Have the user restart the mini-app authorization to generate a fresh callback token.
- Verify the Douyin mini-app appid/secret in config match the app that produced the callback.
- Check code2Session for error details (Douyin returns errcode/errmsg) and log them at the service layer.
- Ensure callbacks are processed once and promptly; do not retry with the same consumed token.
Defensive patterns
Strategy: try-catch
Try / catch
try {
await douyinAuth.exchangeCode({ token: callbackToken, ... })
} catch (e) {
if (e.code === 'ChannelAccessTokenFailed') {
// token invalid/expired/consumed: do NOT retry with the same token
return { error: 'session expired, please restart mini-app authorization' }
}
throw e
} Prevention
- Process mini-app callbacks immediately; the token is short-lived and single-use.
- Never replay or cache callback tokens across attempts.
- Verify mini-app appid/secret per environment (CN vs Intl) before deploy.
- Log code2Session errcode/errmsg at the service layer for diagnosis.
When it happens
Trigger: Mini-app callback where the temporary `token` is invalid, expired, or already consumed, causing douyinMiniAppService.code2Session to return null/undefined or a session without openid.
Common situations: User delayed completing the mini-app flow past token TTL, replayed callback (token single-use), wrong mini-app appid/secret configured so Douyin rejects the session lookup, or network failure silently swallowed upstream.
Related errors
- ChannelAuthorizationFailed
- ChannelAuthRefreshTokenMissing
- ChannelAuthPlatformUidMissing
- ChannelAuthCsrfInvalid
- ChannelAuthCodeMissing
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/c744eae11ee8afd9.
Report an issue: GitHub.