{"record":{"id":"379c89d43b87ae96","repo":"yikart/AiToEarn","slug":"rating-like-unlike","errorCode":null,"errorMessage":"参数错误: rating必须为like或unlike","messagePattern":"参数错误: rating必须为like或unlike","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"project/aitoearn-electron/server/src/modules/plat/tiktok/tiktok.controller.ts","lineNumber":369,"sourceCode":"      required: ['accountId', 'videoId', 'rating']\n    }\n  })\n  async rateVideo(\n    @GetToken() systemToken: TokenInfo,\n    @Body('videoId') videoId: string,\n    @Body('accountId') accountId: string,\n    @Body('rating') rating: string\n  ) {\n    const userId = systemToken.id;\n    if (!videoId || !userId || !accountId) {\n      throw new BadRequestException('videoId, userId和accountId是必须的');\n    }\n\n    const accessToken = await this.tikTokAuthService.getUserAccessToken(accountId);\n\n    // 在方法开始处验证\n    if (![\"like\", \"unlike\"].includes(rating)) {\n      throw new BadRequestException('参数错误: rating必须为like或unlike');\n    }\n\n    // 后续处理\n    if (rating === \"like\") {\n      return this.tikTokService.likeVideo(accessToken, userId, accountId, videoId);\n    } else {\n      return this.tikTokService.unlikeVideo(accessToken, userId, accountId, videoId);\n    }\n  }\n\n  /**\n   * 搜索TikTok视频\n   */\n  @Get('search')\n  @ApiOperation({ summary: '搜索TikTok视频' })\n  async searchVideos(\n    @GetToken() systemToken: TokenInfo,\n    @Query() filterDto: TikTokVideoFilterDto","sourceCodeStart":351,"sourceCodeEnd":387,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-electron/server/src/modules/plat/tiktok/tiktok.controller.ts#L351-L387","documentation":"After resolving the access token, rateVideo enforces an allow-list: rating must be exactly 'like' or 'unlike'. Any other value (wrong case, 'un_like', 'LIKED', numeric codes, etc.) throws this 400 BadRequestException. This is an enum-value validation error, not a missing-field error.","triggerScenarios":"Posting rating values such as 'Like', 'dislike', 'like ', 1, or undefined to the rate-video endpoint.","commonSituations":"UI sending human-readable labels instead of enum values; case-sensitivity bugs; localized strings passed as rating.","solutions":["Send the literal lowercase strings 'like' or 'unlike' as rating.","Normalize/trim/lowercase the rating value on the client before sending.","Constrain UI controls to a two-option toggle mapped to the allowed enum values."],"exampleFix":"// before\nawait api.post('/tiktok/video/rate', { videoId, accountId, rating: 'Like' });\n// after\nconst rating = action === 'like' ? 'like' : 'unlike';\nawait api.post('/tiktok/video/rate', { videoId, accountId, rating });","handlingStrategy":"validation","validationCode":"const ALLOWED_RATINGS = ['like', 'unlike'] as const;\nif (!ALLOWED_RATINGS.includes(rating as any)) {\n  throw new Error(`rating must be like or unlike, got: ${rating}`);\n}","typeGuard":"type Rating = 'like' | 'unlike';\nfunction isRating(v: unknown): v is Rating {\n  return v === 'like' || v === 'unlike';\n}","tryCatchPattern":"try {\n  await api.post('/tiktok/video/rate', { videoId, accountId, rating });\n} catch (e) {\n  if (e.response?.status === 400 && String(e.response.data?.message).includes('rating')) {\n    console.warn('Invalid rating value, expected like|unlike');\n  }\n}","preventionTips":["Define a Rating union type and derive UI options from it.","Normalize user input (trim + lowercase) before mapping to the enum.","Never pass raw localized labels as rating values."],"tags":["bad-request","validation","enum","tiktok"],"backgroundTag":"invalid-enum-value","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}