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

  1. Have the user restart the mini-app authorization to generate a fresh callback token.
  2. Verify the Douyin mini-app appid/secret in config match the app that produced the callback.
  3. Check code2Session for error details (Douyin returns errcode/errmsg) and log them at the service layer.
  4. 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

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


AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31). Data as JSON: /api/errors/c744eae11ee8afd9. Report an issue: GitHub.