{"record":{"id":"28ac67db729d76a5","repo":"yikart/AiToEarn","slug":"id-myrating","errorCode":null,"errorMessage":"只能选择一个参数: id, myRating","messagePattern":"只能选择一个参数: id, myRating","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"warning","filePath":"project/aitoearn-electron/server/src/modules/plat/youtube/youtube.controller.ts","lineNumber":365,"sourceCode":"    return this.youtubeService.getVideoCategoriesList(accessToken, id, regionCode);\n  }\n\n  @ApiOperation({ summary: '获取视频列表' })\n  @Get('videos/list')\n  async getVideosList(\n    @GetToken() token: TokenInfo,\n    @Query('accountId') accountId: string,\n    @Query('id') id?: string,\n    @Query('myRating') myRating?: string,\n    @Query('maxResults') maxResults?: string,\n    @Query('pageToken') pageToken?: string,\n    ) {\n    // 校验确保只有一个参数传递\n    const params = [id, myRating];\n    const nonEmptyParams = params.filter(param => param !== undefined && param !== null && param !== '');\n\n    if (nonEmptyParams.length > 1) {\n      throw new BadRequestException('只能选择一个参数: id, myRating');\n    }\n    const accessToken = await this.youtubeAuthService.getUserAccessToken(accountId);\n    return this.youtubeService.getVideosList(accessToken, id, myRating, maxResults, pageToken);\n  }\n\n  @ApiOperation({ summary: '视频上传' })\n  @UseInterceptors(FileInterceptor('file'))\n  @Post('videos/upload')\n  async videoUpload(\n    @GetToken() token: TokenInfo,\n    @Body('accountId') accountId: string,\n    @UploadedFile() file: Express.Multer.File,\n    @Body('title') title: string,\n    @Body('description') description: string,\n    @Body('keywords') keywords?: string,\n    @Body('categoryId') categoryId?: string,\n    @Body('privacyStatus') privacyStatus?: string,\n    @Body('publishAt') publishAt?: Date","sourceCodeStart":347,"sourceCodeEnd":383,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-electron/server/src/modules/plat/youtube/youtube.controller.ts#L347-L383","documentation":"The YouTube controller's getVideosList endpoint enforces a mutually-exclusive parameter rule: callers may pass `id` (a specific video ID) OR `myRating` (list my rated videos), but not both. When both are non-empty (not undefined/null/''), the controller throws BadRequestException with this message before any YouTube API call is made. It is a client-side input validation guard, not a Google API error.","triggerScenarios":"Calling GET /youtube/videos with both query params set, e.g. ?id=abc123&myRating=like, or passing empty-string-coerced values that the filter treats as non-empty (any param !== undefined && !== null && !== '').","commonSituations":"Frontend code building query strings from form state where both fields are filled; SDK wrappers that always serialize both optional params (sending myRating='' plus a real id); API consumers copying example URLs and leaving a second param populated.","solutions":["Send only one of `id` or `myRating`; omit or leave empty the other query parameter.","Fix the frontend/SDK to skip undefined/null/empty-string params when building the request.","If both pieces of data are needed, make two separate calls: one by `id`, one by `myRating`.","Reproduce locally with curl using a single param to confirm the endpoint works: /youtube/videos?myRating=like&accountId=..."],"exampleFix":"// before\nawait api.get('/youtube/videos', { params: { accountId, id: videoId, myRating: rating } });\n// after\nawait api.get('/youtube/videos', { params: { accountId, ...(rating ? { myRating: rating } : { id: videoId }) } });","handlingStrategy":"validation","validationCode":"const params = [videoId, myRating].filter(v => v !== undefined && v !== null && v !== '');\nif (params.length > 1) throw new Error('Pass only one of: id, myRating');\nif (params.length === 0) throw new Error('One of id or myRating is required');","typeGuard":"function hasSingleParam<T extends Record<string, unknown>>(o: T, keys: (keyof T)[]): boolean {\n  const filled = keys.filter(k => o[k] !== undefined && o[k] !== null && o[k] !== '');\n  return filled.length === 1;\n}","tryCatchPattern":"try {\n  const videos = await client.getVideosList(accountId, videoId, undefined, maxResults);\n} catch (e) {\n  if (String(e.message).includes('只能选择一个参数')) {\n    console.warn('Sent both id and myRating; retrying with id only');\n  } else throw e;\n}","preventionTips":["Build query params via a helper that drops undefined/null/empty-string values.","Enforce single-choice in UI forms (radio group, not two independent inputs).","Add a client-side assertion before serializing request params.","Never hardcode default values for optional mutually-exclusive params."],"tags":["bad-request","input-validation","youtube-api","mutually-exclusive-params"],"backgroundTag":"mutually-exclusive-params","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}