yikart/AiToEarn · error · BadRequestException

获取用户信息失败: ${error.response?.data?.error?.message || error.me

Error message

获取用户信息失败: ${error.response?.data?.error?.message || error.message || error.code}

What it means

A BadRequestException thrown by getTikTokUserProfile when the GET to TikTok's /v2/user/info/ endpoint fails or returns an error envelope. It extracts the nested error.message from TikTok's { error: { code, message } } response shape, falling back to axios error.message or error.code.

Source

Thrown at project/aitoearn-electron/server/src/modules/plat/tiktok/tiktok.auth.service.ts:326

          params: {
            fields: 'open_id,union_id,avatar_url,bio_description,profile_deep_link,is_verified,follower_count,following_count,likes_count,video_count,username, display_name',
            // open_id: openId
          },
          headers: {
            'Authorization': `Bearer ${accessToken}`
          }
        })
      );

      console.log(data)
      // if (data.error) {
      //   throw new BadRequestException(`获取用户信息失败: ${data.error.message}`);
      // }

      return data.data.user;
    } catch (error) {
      this.logger.error('获取TikTok用户信息失败:', error);
      throw new BadRequestException(`获取用户信息失败: ${error.response?.data?.error?.message || error.message || error.code}`);
    }
  }

  /**
   * 更新TikTok账户信息
   * @param userId 用户ID
   * @param tikTokId TikTok用户ID
   * @param accessToken 访问令牌
   * @param refreshToken 刷新令牌
   * @param expires_in 令牌有效期(秒)
   */
  async updateTikTokAccountInfo(
    userId: string,
    tikTokId: string,
    accessToken: string,
    refreshToken: string,
    expires_in: number
  ): Promise<void> {

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Read the nested error message — TikTok names the failing scope or auth problem explicitly.
  2. Ensure the authorize URL requests user.info.basic (and user.info.profile as needed) in its scope parameter.
  3. Verify the access_token used is the current one from the latest token exchange, not a stale Redis entry.
  4. If the token expired, run refreshAccessToken to mint a new one before calling the profile endpoint.

Example fix

// before
const data = await firstValueFrom(this.httpService.get(url, { headers: { Authorization: `Bearer ${accessToken}` } }));
return data.data.user;
// after
if (data.data?.error?.code) {
  throw new BadRequestException(`获取用户信息失败: ${data.data.error.code} - ${data.data.error.message}`);
}
return data.data.user;
Defensive patterns

Strategy: type-guard

Validate before calling

// before calling user info, confirm token shape and scope
if (!accessToken || accessToken.length < 20) throw new Error('valid access_token required');
// ensure the authorize URL included scope=user.info.basic

Type guard

function isTikTokUserPayload(data: unknown): data is { data: { user: { open_id: string; display_name?: string } } } {
  return typeof data === 'object' && data !== null &&
    typeof (data as any).data?.user?.open_id === 'string';
}

Try / catch

try {
  const profile = await api.getTikTokUserProfile(token);
} catch (e) {
  const msg = (e as any).response?.data?.error?.message ?? (e as Error).message;
  if (/access_token|invalid/i.test(msg)) {
    token = await api.refreshTikTokToken(accountId);
    return retryProfile(token);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling user info with an access_token that is expired, revoked, or lacks the user.info.basic scope; the token was refreshed/rotated between exchange and profile fetch; TikTok returns 4xx with an error envelope.

Common situations: Missing user.info.basic scope in the authorize URL's scope parameter, access token expired (TikTok access tokens last ~24h), token stored in Redis was overwritten or evicted, wrong API version path.

Related errors


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