{"record":{"id":"5c46603d423be569","repo":"yikart/AiToEarn","slug":"channelaccesstokenfailed-5c4660","errorCode":"ChannelAccessTokenFailed","errorMessage":"ResponseCode.ChannelAccessTokenFailed","messagePattern":"ResponseCode\\.ChannelAccessTokenFailed","errorType":"exception","errorClass":"BilibiliPlatformException","httpStatus":null,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/bilibili/bilibili.service.ts","lineNumber":86,"sourceCode":"    refreshToken: string\n    expiresAt: Date\n  }> {\n    const body = new URLSearchParams({\n      client_id: this.cfg.clientId,\n      client_secret: this.cfg.clientSecret,\n      grant_type: BilibiliOAuthGrantType.AuthorizationCode,\n      code,\n    })\n    const response = await this.platformHttp.post<BilibiliApiResponse<{\n      access_token: string\n      refresh_token: string\n      expires_in: number\n    }>>('https://api.bilibili.com/x/account-oauth2/v1/token', body.toString(), {\n      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n    })\n\n    if (!response.data.data) {\n      throw new BilibiliPlatformException({\n        code: ResponseCode.ChannelAccessTokenFailed,\n        category: PlatformErrorCategory.Auth,\n        context: { endpoint: 'POST https://api.bilibili.com/x/account-oauth2/v1/token' },\n        cause: { type: PlatformErrorCauseType.Platform },\n      })\n    }\n\n    const { access_token, refresh_token, expires_in } = response.data.data\n\n    return {\n      accessToken: access_token,\n      refreshToken: refresh_token,\n      expiresAt: new Date(Date.now() + expires_in * 1000),\n    }\n  }\n\n  async refreshAccessToken(refreshToken: string): Promise<{\n    accessToken: string","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/bilibili/bilibili.service.ts#L68-L104","documentation":"BilibiliService.exchangeCode swaps the OAuth authorization code for tokens at api.bilibili.com/x/account-oauth2/v1/token. If the response has no data payload, it throws BilibiliPlatformException with code ChannelAccessTokenFailed, category Auth, cause Platform — i.e. Bilibili did not return tokens.","triggerScenarios":"OAuth callback invokes exchangeCode and Bilibili's token endpoint responds with success envelope but empty/missing data — invalid or expired authorization code, code already redeemed, mismatched clientId/clientSecret, or redirect URI mismatch.","commonSituations":"User retries the callback URL (code single-use); app credentials changed in Bilibili open platform; redirect_uri differs between authorize and token requests; clock drift or expired code due to slow processing.","solutions":["Restart the OAuth flow: generate a fresh authorization code and exchange it immediately, once.","Verify clientId/clientSecret and redirect_uri exactly match the Bilibili open-platform app config.","Inspect Bilibili's response body/logs (message/code fields) for the platform-side rejection reason.","Handle ChannelAccessTokenFailed by redirecting the user to re-authorize rather than retrying the same code."],"exampleFix":"// before\n// reusing a stored code\nawait bilibiliService.exchangeCode(oldCode)\n\n// after\n// always exchange a fresh code from the callback\nconst result = await bilibiliService.exchangeCode(query.code) // one-time use","handlingStrategy":"try-catch","validationCode":"if (!query.code) return redirect('/auth/bilibili') // no code at all\n// codes are single-use and short-lived: never cache or replay them","typeGuard":null,"tryCatchPattern":"try {\n  tokens = await bilibiliService.exchangeCode(code)\n} catch (e) {\n  if (e.code === 'ChannelAccessTokenFailed') {\n    // invalid/expired/replayed code or bad app credentials\n    return redirect('/auth/bilibili?restart=1') // force fresh OAuth flow\n  }\n  throw e\n}","preventionTips":["Exchange the code immediately in the callback; never reuse it","Keep clientId/clientSecret/redirect_uri identical across authorize and token requests","Log Bilibili's raw response body for the platform-side error message"],"tags":["bilibili","oauth","auth","token-exchange"],"backgroundTag":"oauth-token-exchange-failed","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}