{"record":{"id":"31755ddd6d7a987a","repo":"yikart/AiToEarn","slug":"error-response-data-error-message","errorCode":null,"errorMessage":"获取用户信息失败: ${error.response?.data?.error?.message || error.message || error.code}","messagePattern":"获取用户信息失败: (.+?)","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"project/aitoearn-electron/server/src/modules/plat/tiktok/tiktok.auth.service.ts","lineNumber":326,"sourceCode":"          params: {\n            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',\n            // open_id: openId\n          },\n          headers: {\n            'Authorization': `Bearer ${accessToken}`\n          }\n        })\n      );\n\n      console.log(data)\n      // if (data.error) {\n      //   throw new BadRequestException(`获取用户信息失败: ${data.error.message}`);\n      // }\n\n      return data.data.user;\n    } catch (error) {\n      this.logger.error('获取TikTok用户信息失败:', error);\n      throw new BadRequestException(`获取用户信息失败: ${error.response?.data?.error?.message || error.message || error.code}`);\n    }\n  }\n\n  /**\n   * 更新TikTok账户信息\n   * @param userId 用户ID\n   * @param tikTokId TikTok用户ID\n   * @param accessToken 访问令牌\n   * @param refreshToken 刷新令牌\n   * @param expires_in 令牌有效期（秒）\n   */\n  async updateTikTokAccountInfo(\n    userId: string,\n    tikTokId: string,\n    accessToken: string,\n    refreshToken: string,\n    expires_in: number\n  ): Promise<void> {","sourceCodeStart":308,"sourceCodeEnd":344,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-electron/server/src/modules/plat/tiktok/tiktok.auth.service.ts#L308-L344","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read the nested error message — TikTok names the failing scope or auth problem explicitly.","Ensure the authorize URL requests user.info.basic (and user.info.profile as needed) in its scope parameter.","Verify the access_token used is the current one from the latest token exchange, not a stale Redis entry.","If the token expired, run refreshAccessToken to mint a new one before calling the profile endpoint."],"exampleFix":"// before\nconst data = await firstValueFrom(this.httpService.get(url, { headers: { Authorization: `Bearer ${accessToken}` } }));\nreturn data.data.user;\n// after\nif (data.data?.error?.code) {\n  throw new BadRequestException(`获取用户信息失败: ${data.data.error.code} - ${data.data.error.message}`);\n}\nreturn data.data.user;","handlingStrategy":"type-guard","validationCode":"// before calling user info, confirm token shape and scope\nif (!accessToken || accessToken.length < 20) throw new Error('valid access_token required');\n// ensure the authorize URL included scope=user.info.basic","typeGuard":"function isTikTokUserPayload(data: unknown): data is { data: { user: { open_id: string; display_name?: string } } } {\n  return typeof data === 'object' && data !== null &&\n    typeof (data as any).data?.user?.open_id === 'string';\n}","tryCatchPattern":"try {\n  const profile = await api.getTikTokUserProfile(token);\n} catch (e) {\n  const msg = (e as any).response?.data?.error?.message ?? (e as Error).message;\n  if (/access_token|invalid/i.test(msg)) {\n    token = await api.refreshTikTokToken(accountId);\n    return retryProfile(token);\n  }\n  throw e;\n}","preventionTips":["Always request user.info.basic scope in the authorize URL.","Refresh expired access tokens before calling user info.","Validate the token exists in Redis before each profile call.","Check TikTok's { error: { code, message } } envelope even on HTTP 200."],"tags":["tiktok","user-info","access-token","scope"],"backgroundTag":"oauth-token-invalid-or-expired","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}